如何让异常从异步方法向上传播到堆栈?(不能使用async或wait关键字)
本文关键字:不能 async 关键字 wait 堆栈 异常 异步方法 传播 | 更新日期: 2023-09-27 18:25:30
请注意这个简单的代码:
try
{
var t = Task.Factory.StartNew<bool>(() => { throw new Exception("aaa"); });
t.ContinueWith(_ => {}, TaskContinuationOptions.OnlyOnRanToCompletion).Wait();
}
catch (Exception exc)
{
Debug.WriteLine(exc);
}
我假设,如果t
有一个与之关联的异常,那么Wait()
将按原样重新抛出此异常。然而,成功的存在只是延续,似乎改变了这种行为。相反,抛出的是一个"任务已取消"异常。
事实上,在Wait()
之前链接TaskContinuationOptions.NotOnRanToCompletion
完成处理程序表明,传递给它的任务没有出现故障,而是被取消了:
t.ContinueWith(_ => { }, TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith(t2 => Debug.Assert(t2.IsCanceled), TaskContinuationOptions.NotOnRanToCompletion)
.Wait();
这一切都有点奇怪。这意味着,我不能只是将我的快乐路径完成处理程序链接起来,让任何异常传播到与等待线程的最终会合。
我在这里错过了什么?
注意
我仅限于.NET 4.0,因此没有await
和async
关键字。
我在这里错过了什么?
您缺少.NET 4.5。如果没有await
和async
关键字,任务仍然很有用,但如果你想要你所说的"快乐之路"行为,你需要升级(请参阅下面的更新)。
因为任务比标准的贯穿代码更复杂,而且它们可以通过各种方式连接在一起,所以您需要直接从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,则可以使用async
和await
关键字,而无需升级到4.5。感谢@zespri指出这一点。
更新2:如果您想在顶级捕获并记录适当的异常,只需养成将.Wait()
方法封装在try/catch
块中的习惯,即可封装给定的异常。
try
{
t.Wait();
}
catch (AggregateException exc)
{
throw new Exception("Task Foo failed to complete", t.Exception);
}