Indenting lambdas and nested actions

前端 未结 2 1297
佛祖请我去吃肉
佛祖请我去吃肉 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:45

    1. I am not sure myself the best way to do indentation. If I were to write an equivalent to your code with minimal change in meaning, I might end up with something like the following. Sorry, it’s not a problem I’ve solved myself:

      Task t1 = Task.Factory.StartNew(
          () =>
          {
              DoSomething();
          })
          .ContinueWith(
              (t2) =>
              {
                  DoSomethingWhenComplete();
              },
              TaskContinuationOptions.OnlyOnRanToCompletion)
          .ContinueWith(
              (t3) =>
              {
                  DoSomethingOnError();
              },
              TaskContinuationOptions.OnlyOnFaulted);
      

      My reasoning behind the indentation I used is that a “child”/“part” of an expression should be indented deeper than the line where its “parent”/“container” begins. In the prior lines, the method’s arguments are part of a method call. So if the method call itself is at one level of indentation, the arguments should be indented one level further:

      MethodCall(
          arg1,
          arg2);
      

      Likewise, both sides of a binary operator such as scope resolution/member access (.) are children of the expression and we can, in a way, think of them all being at the same level. For example, there may be a.b.c or a + b + c, and I would consider each element to be a child of the overall expression. Thus, since each .ContinueWith() is part of the overall statement started on the first line, they should also each be indented just like in the following multiline arithmetic expression:

      var x = 1
          + 2
          + SomethingComplicated();
      
    2. One big point of the Task Parallel Library is to enable you to continue writing “normal” looking code. What you have done is written a lot of code and calls to the TPL to reimplement a feature that already exists in C#—the try{}catch{}finally{} block. Also, using Task.Run(), assuming you just wanted to hoist the operation to the threadpool (but you can easily change this back to use your custom TaskFactory).

      Task t1 = Task.Run(
          () =>
          {
              try
              {
                  DoSomething();
              }
              catch (Exception ex)
              {
                  DoSomethingOnError(ex);
                  // Error: do not proceed as usual, but do not mark t1
                  // as faulted. We did something magical in
                  // DoSomethingOnError() that addresses the error so
                  // that it doesn’t need to be reported back to our
                  // caller.
                  return;
              }
      
              // Completed successfully!
              DoSomethingWhenComplete();
          });
      

      The way I handled the error in catch{} by calling DoSomethingOnError() and immediately returning simulates the way faultedTask.ContinueWith(action, TaskContinuationOptions.OnlyOnFaulted) behaves. The result of that expression is a Task representing the continuation. The continuation’s Task will only fault if the continuation itself faults. So by assigning the continuation to t1 rather than the original Task, you are effectively catching and swallowing the exception, just like how I catch and swallow it in my try{}catch{}. Just the lambda I wrote does this much more clearly than trying to compose a bunch of continuations manually.

      As @Noseratio says, you get much clearer code if you use async/await when it makes sense to do so. For offloading some standard, non-async method calls to the threadpool as your question suggests, it is not obvious that moving to async/await would actually help you. But replacing a bunch of TPL API calls with a single lambda does seem like a worthwhile refactor.

提交回复
热议问题