请注意这个简单的代码:
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,因此没有await
和async
个关键字。
答案 0 :(得分:2)
我在这里缺少什么?
您缺少.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,you can似乎使用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);
}