在任务中抛出异常 - “等待”与等待()

时间:2011-09-07 20:44:08

标签: c# exception-handling task-parallel-library async-await parallel-extensions

static async void Main(string[] args)
{
    Task t = new Task(() => { throw new Exception(); });

    try
    {                
        t.Start();
        t.Wait();                
    }
    catch (AggregateException e)
    {
        // When waiting on the task, an AggregateException is thrown.
    }

    try
    {                
        t.Start();
        await t;
    }
    catch (Exception e)
    {
        // When awating on the task, the exception itself is thrown.  
        // in this case a regular Exception.
    }           
}

在TPL中,当在一个Task中抛出一个异常时,它被一个AggregateException包装 但使用等待关键字时也不会发生同样的情况 这种行为有什么解释?

3 个答案:

答案 0 :(得分:9)

目标是使其外观/行为与同步版本相同。 Jon Skeet在他的Eduasync系列中做了很好的解释,特别是这篇文章:

http://codeblog.jonskeet.uk/2011/06/22/eduasync-part-11-more-sophisticated-but-lossy-exception-handling/

答案 1 :(得分:2)

在TPL中使用AggregateException因为你可以在等待操作中有多个任务(任务可以附加子任务),所以很多任务都可以抛出异常。查看子任务中的例外部分

https://msdn.microsoft.com/ru-ru/library/dd997417(v=vs.110).aspx

await中,您总是只有一项任务

另见https://msdn.microsoft.com/ru-ru/library/dd997415(v=vs.110).aspx

答案 2 :(得分:0)

Stephen Toub很好地解释了为什么Task.Wait()和await之间的异常类型有所不同:

Task Exception Handling in .NET 4.5

  

在.NET 4中设计Task.Wait时,我们选择始终传播   骨料。该决定受到不覆盖需求的影响   细节,但根据当时任务的主要用例,   fork / join并行性的概念,其中可能有多个异常   很常见。

     

与任务类似,请高层等待(即前进)   直到任务完成才创建),“等待任务”代表   不同的主要方案集。而不是被用于   fork / join并行性,“等待任务”的最常见用法是   采取顺序,同步的代码并将其转换为   顺序的异步代码段。在代码中的位置   您执行同步操作,将其替换为   任务代表的异步操作并“等待”它。因此,   虽然您当然可以使用await进行fork / join操作(例如   利用Task.WhenAll),情况并非80%。此外,.NET 4.5   看到介绍   System.Runtime.ExceptionServices.ExceptionDispatchInfo,它解决了   允许您封送跨线程异常的问题   不会丢失堆栈跟踪和Watson存储桶等异常详细信息。   给定一个异常对象,将其传递给   ExceptionDispatchInfo.Create,它返回一个ExceptionDispatchInfo   对象,该对象包含对Exception对象的引用和的副本   其细节。当需要抛出异常时,   ExceptionDispatchInfo的Throw方法用于还原内容   并抛出异常而不会丢失原始信息   (当前的调用堆栈信息会附加到已经   存储在异常中)。

     

考虑到这一点,又可以选择始终抛出第一个   或总是抛出总计,对于“等待”,我们选择总是抛出   首先。但是,这并不意味着您无权访问   相同的细节。在任何情况下,任务的“例外”属性仍然   返回一个包含所有异常的AggregateException,因此   您可以抓住任何抛出的东西,然后回去咨询   Task.Exception必要时。是的,这导致   在“ task.Wait()”和“ await”之间切换时的异常行为   任务”,但我们认为这是两个弊端的明显减少。