如何让异常从异步方法向上传播? (不能使用async或等待关键字)

时间:2013-07-30 21:38:19

标签: c# .net asynchronous .net-4.0

请注意这个简单的代码:

   try
   {
     var t = Task.Factory.StartNew<bool>(() => { throw new Exception("aaa"); });
     t.ContinueWith(_ => {}, TaskContinuationOptions.OnlyOnRanToCompletion).Wait();
   }
   catch (Exception exc)
   {
     Debug.WriteLine(exc);
   }

我假设如果t有一个与之关联的异常,那么此异常将由Wait()重新抛出。然而,仅成功的存在似乎改变了这种行为。引发的是“A task was canceled”异常。

实际上,在TaskContinuationOptions.NotOnRanToCompletion之前链接一个Wait()完成处理程序会发现传递给它的任务没有出错,但是被取消了:

t.ContinueWith(_ => { }, TaskContinuationOptions.OnlyOnRanToCompletion)
 .ContinueWith(t2 => Debug.Assert(t2.IsCanceled), TaskContinuationOptions.NotOnRanToCompletion)
 .Wait();

这有点奇怪。这意味着,我不能只链接我的快乐路径完成处理程序,让任何异常只是传播到与等待线程的最终集合。

我在这里缺少什么?

注意

我仅限于.NET 4.0,因此没有awaitasync个关键字。

1 个答案:

答案 0 :(得分:2)

  

我在这里缺少什么?

您缺少.NET 4.5。如果没有awaitasync关键字,任务仍然有用,但如果您想要谈论的“快乐路径”行为,则需要升级(请参阅更新如下)。

因为任务比标准的贯穿代码更复杂,并且因为它们可以通过各种方式连接在一起,所以你需要直接从Task请求异常,而不是抛出异常。致电.Wait()

var t = Task.Factory.StartNew<bool>(() => { throw new Exception("aaa"); });
   try
   {
     t.ContinueWith(_ => {}, TaskContinuationOptions.OnlyOnRanToCompletion)
        .Wait();
   }
   catch (AggregateException exc)
   {
     Debug.WriteLine(exc.InnerExceptions[0]);// "A task was canceled"
     Debug.WriteLine(t.Exception.InnerExceptions[0]);// "aaa"
   }

更新:如果您使用的是Visual Studio 2012,you can似乎使用asyncawait关键字而不升级到4.5。感谢@zespri指出这一点。

更新2:如果要捕获并在顶层记录相应的异常,只需养成在.Wait()块中包装try/catch方法的习惯,换行给定的例外。

try
{
  t.Wait();
}
catch (AggregateException exc)
{
  throw new Exception("Task Foo failed to complete", t.Exception);
}