Indenting lambdas and nested actions

前端 未结 2 1303
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-05 07:29

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         


        
2条回答
  •  佛祖请我去吃肉
    2021-01-05 07:48

    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).

提交回复
热议问题