C# 缩进lambda和嵌套操作
当使用lambdas时,通常是在TPL上,我会在缩进中迷失。。。是否有一些最佳实践来设置此格式?例如,以以下代码为例:C# 缩进lambda和嵌套操作,c#,lambda,coding-style,task-parallel-library,C#,Lambda,Coding Style,Task Parallel Library,当使用lambdas时,通常是在TPL上,我会在缩进中迷失。。。是否有一些最佳实践来设置此格式?例如,以以下代码为例: Task t1 = factory.StartNew(() => { DoSomething(); } .ContinueWith((t2) => { DoSomethingWhenComplete(); }, TaskContinuationOptions.OnlyOnRanToCompletion) ).ContinueWith((t3) =&g
Task t1 = factory.StartNew(() =>
{
DoSomething();
}
.ContinueWith((t2) =>
{
DoSomethingWhenComplete();
}, TaskContinuationOptions.OnlyOnRanToCompletion)
).ContinueWith((t3) =>
{
DoSomethingOnError();
}, TaskContinuationOptions.OnlyOnFaulted);
Task t1 = factory.StartNew(() =>
{
DoSomething();
});
t1.ContinueWith((t2) =>
{
DoSomethingWhenComplete();
}, TaskContinuationOptions.OnlyOnRanToCompletion);
t1.ContinueWith((t2) =>
{
DoSomethingOnError();
}, TaskContinuationOptions.OnlyOnFaulted);
这可能有效,但您缺少另一个状态:onlyonCancelled
。我宁愿在同一个地方处理t1
的所有完成状态:
Task t1 = factory.StartNew(() =>
{
DoSomething();
}).ContinueWith((t2) =>
{
if (t2.IsCanceled)
DoSomethingWhenCancelled();
else if (t2.IsFaulted)
DoSomethingOnError(t1.Exception);
else
DoSomethingWhenComplete();
});
这可能仍然缺少一件事:您的代码将在没有同步上下文的随机池线程上继续。例如,如果在UI线程上调用ContinueWith
,则无法访问DoSomething*
方法中的UI。如果这不是您所期望的,请明确指定要继续的任务计划程序:
Task t1 = factory.StartNew(() =>
{
DoSomething();
}).
ContinueWith((t2) =>
{
if (t1.IsCanceled)
DoSomethingWhenCancelled();
else if (t1.IsFaulted)
DoSomethingOnError(t1.Exception);
else
DoSomethingWhenComplete();
}, TaskScheduler.FromCurrentSynchronizationContext());
如果您需要以.NET 4为目标,但是使用VS201+作为开发环境,考虑使用<代码>异步/等待< /代码>,而不是<代码>继续> 。编写代码更容易,可读性更高,并且可以使用
try/catch
进行结构化错误处理
如果不能使用异步/等待,请考虑使用Stephen Toub的任务链模式(更多细节)。p>
Task t1 = Task.Factory.StartNew(
() =>
{
DoSomething();
})
.ContinueWith(
(t2) =>
{
DoSomethingWhenComplete();
},
TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith(
(t3) =>
{
DoSomethingOnError();
},
TaskContinuationOptions.OnlyOnFaulted);
我使用缩进的原因是,表达式的“子”/“部分”缩进应该比其“父”/“容器”开始的行更深。在前面的几行中,方法的参数是方法调用的一部分。因此,如果方法调用本身处于一个缩进级别,则参数应进一步缩进一个级别:
MethodCall(
arg1,
arg2);
类似地,二元运算符(如作用域解析/成员访问(
)的两侧都是表达式的子级,我们可以在某种程度上认为它们都处于同一级别。例如,可能存在<代码> A.B.C.<代码>或<代码> A+B+C,并且我认为每个元素都是整体表达式的子元素。因此,由于每个.ContinueWith()
都是从第一行开始的整个语句的一部分,因此它们也应该像下面的多行算术表达式一样缩进:
var x = 1
+ 2
+ SomethingComplicated();
任务工厂)
我在catch{}
中处理错误的方法是调用DoSomethingOnError()
并立即返回,模拟了faultedTask.ContinueWith(action,TaskContinuationOptions.OnlyOnFaulted)
的行为方式。该表达式的结果是表示延续的任务。只有当延续本身出现故障时,延续的任务才会出现故障。因此,通过将continuation分配给t1
而不是原始的任务
,您可以有效地捕获并吞咽异常,就像我在try{}catch{/code>中捕获并吞咽异常一样。仅仅是我写的lambda就比手动编写一组连续体要清楚得多
同样,如果在合理的时候使用async
/wait
,代码会更清晰。如您的问题所示,对于卸载对线程池的一些标准、非异步方法调用,转到async
/wait
实际上对您没有帮助。但是用一个lambda替换一堆tplapi调用看起来确实是一个值得重构的过程
美好的但是考虑移动<代码> StaseNeX<代码>下一行到同一个缩进级别,如<代码>继续> 。@ Listman,我现在要坚持我的丑陋缩进;我试着用我的推理更新我的答案。基本上,我不想在前一行缩进的基础上,将参数缩进一个函数超过一个级别,因为我通常不会在一个更简单的方法调用中进行缩进。我希望所有缩进的连续体都能说明它们是从第1行开始的语句的一部分。
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();
});