2013-07-30 40 views
1

请遵守这个简单的代码:如何让异常从异步方法传播堆栈? (不能使用异步或等待关键字)

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,所以没有awaitasync关键字。

+4

如果你不知道,你可以使用异步的.NET 4.0/AWAIT http://blogs.msdn.com/b/bclteam/archive/2013/04/17/microsoft-bcl -async-is-now-stable.aspx –

+0

@zespri:非常好! –

+0

有趣。以下是一篇指导性文章:http://blogs.msdn.com/b/bclteam/archive/2012/10/22/using-async-await-without-net-framework-4-5.aspx – StriplingWarrior

回答

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:如果你想赶上,并在顶层记录相应的例外,只要包装在try/catch块你.Wait()方法的习惯,换了给定异常。

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

不幸的是,'' t'不在实际应用中的捕手范围内。 – mark

+0

@mark:考虑问自己为什么不。调用'.Wait()'的代码将在try/catch块中包装该调用并记录或包装相应的异常似乎是合理的,因为这是知道它正在等待异步任务的代码。如果这看起来不适合你,也许该方法本身需要返回一个Task,并让调用方法执行'.Wait()'。 – StriplingWarrior