When using lambdas, usually on TPL, I get lost on indentation... Are there some best practices to format this? For example, take this code:
Task t1 = factory.StartNew(() =>
{
DoSomething();
}
.ContinueWith((t2) =>
{
DoSomethingWhenComplete();
}, TaskContinuationOptions.OnlyOnRanToCompletion)
).ContinueWith((t3) =>
{
DoSomethingOnError();
}, TaskContinuationOptions.OnlyOnFaulted);
- Is my "indentation" correct?
- In that example, I want to execute t1, then if it finished OK, execute t2, and on error execute t3. But looks as though t3 is a continuation from t2, not from t1... What do I need to fix in that code to get the correct behaviour? I think that I'm lost on that indentation or missing some parenthesis...
There are some best practice to format this?
I'm not aware of any. Your formatting looks OK by me (besides the notes below). Alternatively, you may just follow Visual Studio automatic formatting (try Format Document from Editor/Advanced menu).
In that example, I want execute t1 then if finish ok execute t2 and on
error execute t3. But looks that t3 is continuation from t2, not from
t1... What I need fix that code to correct behaviour? I think that I'm
lost on that indentation or missing some parenthesis...
The code fragment from your question would not even compile. You probably wanted this:
Task t1 = factory.StartNew(() =>
{
DoSomething();
});
t1.ContinueWith((t2) =>
{
DoSomethingWhenComplete();
}, TaskContinuationOptions.OnlyOnRanToCompletion);
t1.ContinueWith((t2) =>
{
DoSomethingOnError();
}, TaskContinuationOptions.OnlyOnFaulted);
This may work, but you're missing another state: OnlyOnCanceled
. I'd rather handle all completion statuses of t1
in the same place:
Task t1 = factory.StartNew(() =>
{
DoSomething();
}).ContinueWith((t2) =>
{
if (t2.IsCanceled)
DoSomethingWhenCancelled();
else if (t2.IsFaulted)
DoSomethingOnError(t1.Exception);
else
DoSomethingWhenComplete();
});
This still might be missing one thing: your code will be continued on a random pool thread without synchronization context. E.g, if you called ContinueWith
on a UI thread, you won't be able to access the UI inside DoSomething*
methods. If that's not what you expected, explicitly specify the task scheduler for continuation:
Task t1 = factory.StartNew(() =>
{
DoSomething();
}).
ContinueWith((t2) =>
{
if (t1.IsCanceled)
DoSomethingWhenCancelled();
else if (t1.IsFaulted)
DoSomethingOnError(t1.Exception);
else
DoSomethingWhenComplete();
}, TaskScheduler.FromCurrentSynchronizationContext());
If you need to target .NET 4.0 but use VS2012+ as your development environment, consider using async/await
and Microsoft.Bcl.Async
instead of ContinueWith
. It's much easier to code, more readable and will give you structured error handling with try/catch
.
If you can't use async/await, consider using Task.Then pattern by Stephen Toub for task chaining (more details here).