在延续链中传播异常的正确方法是什么?
t.ContinueWith(t2 =>
{
if(t2.Exception != null)
throw t2.Exception;
/* Other async code. */
})
.ContinueWith(/*...*/);
t.ContinueWith(t2 =>
{
if(t2.IsFaulted)
throw t2.Exception;
/* Other async code. */
})
.ContinueWith(/*...*/);
t.ContinueWith(t2 =>
{
if(t2.Exception != null)
return t2;
/* Other async code. */
})
.ContinueWith(/*...*/);
t.ContinueWith(t2 =>
{
if(t2.IsFaulted)
return t2;
/* Other async code. */
})
.ContinueWith(/*...*/);
t.ContinueWith(t2 =>
{
t2.Wait();
/* Other async code. */
})
.ContinueWith(/*...*/);
t.ContinueWith(t2 =>
{
/* Other async code. */
}, TaskContinuationOptions.NotOnFaulted) // Don't think this one works as expected
.ContinueWith(/*...*/);
最佳答案
TaskContinuationOptions.OnlyOn...
可能会出现问题,因为如果不满足其条件,它们会导致延续被取消。在理解这一点之前,我编写的代码存在一些微妙的问题。
像这样的链式延续实际上很难做到正确。 到目前为止,最简单的修复方法是使用新的 .NET 4.5 await
功能。这使您几乎可以忽略正在编写异步代码的事实。您可以像在同步等效项中一样使用 try/catch block 。对于 .NET 4,可以使用 async targeting pack .
如果您使用的是 .NET 4.0,最直接的方法是从每个延续中的先行任务访问 Task.Result
,或者,如果它没有返回结果,则使用 Task.Wait()
就像您在示例代码中所做的那样。但是,您最终可能会得到一个嵌套的 AggregateException
对象树,稍后您需要解开这些对象才能获得“真正的”异常。 (同样,.NET 4.5 使这更容易。虽然 Task.Result
抛出 AggregateException
,Task.GetAwaiter().GetResult()
— 这是否则等效——抛出底层异常。)
重申这实际上不是一个微不足道的问题,您可能对 Eric Lippert 关于 C# 5 异步代码中异常处理的文章感兴趣 here和 here .
关于c# - 在延续链中传播异常的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15478882/