简体   繁体   English

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

[英]How to let exception propagate up the stack from async methods? (cannot use async or await keywords)

Please, observe this simple code: 请遵守以下简单代码:

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

I assumed that if t has an exception associated with it, then this exception will be rethrown as is by Wait() . 我假设如果t具有与之关联的异常,那么该异常将被Wait()照原样重新抛出。 However, the presence of the success only continuation seems to change this behavior. 但是,仅成功继续的存在似乎改变了这种行为。 What is thrown instead is a "A task was canceled" exception. 而是引发了“任务已取消”异常。

Indeed, chaining a TaskContinuationOptions.NotOnRanToCompletion completion handler just before Wait() reveals that the task passed to it is not faulted, but cancelled: 确实,在Wait()之前链接TaskContinuationOptions.NotOnRanToCompletion完成处理程序可以发现传递给它的任务不是错误的,而是被取消的:

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

This is all a bit strange. 这有点奇怪。 It means, I cannot just chain my happy path completion handlers letting any exceptions just propagate to the ultimate rendezvous with the waiting thread. 这意味着,我不能仅仅链接我的快乐路径完成处理程序,让任何异常仅通过等待线程传播到最终集合点。

What am I missing here? 我在这里想念什么?

NOTE 注意

I am limited to .NET 4.0, so no await and async keywords. 我仅限于.NET 4.0,因此没有awaitasync关键字。

What am I missing here? 我在这里想念什么?

You are missing .NET 4.5. 您缺少.NET 4.5。 Tasks are still useful without the await and async keywords, but if you want the "happy path" behavior you're talking about, you'll need to upgrade (see update below). 如果没有awaitasync关键字,任务仍然很有用,但是如果您要谈论的是“快乐之路”行为,则 需要升级 (请参阅下面的更新)。

Because tasks are more complicated than standard run-through code, and because they can be joined together in various ways, you'll need to ask for the exception directly from the Task , rather than the exception thrown by the call to .Wait() . 因为任务比标准的贯穿代码要复杂得多,并且可以通过多种方式将它们连接在一起,所以您需要直接从Task请求异常,而不是通过调用.Wait()引发的异常.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"
   }

Update: If you are using Visual Studio 2012, it appears that you can use the async and await keywords without upgrading to 4.5. 更新:如果您使用的是Visual Studio 2012,则似乎可以使用asyncawait关键字而无需升级到4.5。 Thanks to @zespri for pointing this out. 感谢@zespri指出这一点。

Update 2: If you want to catch and log the appropriate exception at the top level, just make a habit of wrapping your .Wait() methods in try/catch blocks, wrap the given exception. 更新2:如果您想在顶层捕获并记录适当的异常,只需养成将.Wait()方法包装在try/catch块中的习惯,请包装给定的异常。

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

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

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