繁体   English   中英

在连续链中传播异常的正确方法是什么?

[英]What is the proper way to propagate exceptions in continuation chains?

在连续链中传播异常的正确方法是什么?

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块。 对于.NET 4,可以使用异步定位包

如果您使用的是.NET 4.0,最简单的方法是从每个延续中的前导任务访问Task.Result ,或者,如果它不返回结果,请使用Task.Wait()就像在示例代码中一样。 但是,您可能最终会得到一个嵌套的AggregateException对象树,稍后您需要解析这些对象才能获得“真正的”异常。 (同样,.NET 4.5使这更容易。当Task.Result抛出AggregateExceptionTask.GetAwaiter().GetResult() - 否则等效 - 抛出基础异常。)

要重申,这其实不是一个简单的问题,你可能会感兴趣的埃里克利珀的异常处理在C#5异步代码的文章在这里这里

如果您不希望在发生异常(即日志记录)时特别执行任何操作,并且只希望传播异常,则只需在抛出异常时(或在取消时)运行continuation。

task.ContinueWith(t =>
{
    //do stuff
}, TaskContinuationOptions.OnlyOnRanToCompletion);

如果您明确要处理异常的情况(可能要进行日志记录,请将抛出的异常更改为其他类型的异常(可能包含其他信息,或隐藏不应公开的信息))然后您可以添加使用OnlyOnFaulted选项的延续(可能除了正常的案例延续)。

OnlyOnFaulted选项适用于前一个Task无法正确执行任务的情况。 一种方法是在每个延续任务中重新抛出异常,但那将是糟糕的设计。

如果要像普通对象一样传递异常,则将其视为一个。 Task返回异常并在Task.Result中使用Task.Result属性。

我们现在在openstack.net SDK中使用的方法是CoreTaskExtensions.cs的扩展方法。

方法有两种形式:

  • Then :continuation返回一个Task ,并自动调用Unwrap()
  • Select :continuation返回一个对象,并且不会调用Unwrap() 此方法仅适用于轻量级延续,因为它始终指定TaskContinuationOptions.ExecuteSynchronously

这些方法具有以下好处:

  1. 当前因出现故障或取消时,避免调用延续方法。
  2. 相反,前提的结果成为链式操作的结果(准确保留异常信息,而不将多个AggregateException包装在异常中)。
  3. 允许调用者编写支持故障前提的延续方法,在这种情况下,仅取消前面的任务绕过延续(为扩展方法指定supportsErrors=true )。
  4. 返回Task Continuations同步执行,并为您调用Unwrap()

以下对比显示了我们如何将此更改应用于最初使用ContinueWithUnwrap CloudAutoScaleProvider.cs
https://github.com/openstacknetsdk/openstack.net/compare/3ae981e9...299b9f67#diff-3

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM