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.
}
}
在第三方公共语言中,当在任务内部抛出异常时,它用AggregateException包装。
但在使用await关键字时,不会发生同样的情况。
对这种行为的解释是什么?
发布于 2011-09-08 17:41:41
我们的目标是让它看起来/行为像同步版本。Jon Skeet在他的Eduasync系列文章中做了很好的解释,特别是这篇文章:
发布于 2017-03-23 18:28:00
在第三方物流中使用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
发布于 2019-07-31 23:10:03
下面是Stephen Toub的详细解释,为什么Task.Wait()和await在异常类型上存在差异:
Task Exception Handling in .NET 4.5
在.NET 4中设计Task.Wait时,我们选择了总是传播聚合。这一决定不仅受到不重写细节的需要的影响,而且还受到当时任务的主要用例的影响,即fork/join并行性,其中潜在的多个异常相当常见。
虽然在高层次上类似于Task.Wait (即直到任务完成才会取得前进的进展),但“等待任务”代表了一组非常不同的主要场景。“等待任务”最常见的用法不是用于fork/join并行性,而是将一个连续的、同步的代码片段转换为一个连续的、异步的代码片段。在代码中执行同步操作的地方,您可以将其替换为由任务表示的异步操作并“等待”它。因此,虽然你当然可以使用await for fork/join操作(例如,利用Task.WhenAll),但它不是80%的情况。此外,Watson 4.5引入了System.Runtime.ExceptionServices.ExceptionDispatchInfo,,它解决了允许您在不丢失堆栈跟踪和.NET存储桶等异常细节的情况下跨线程编组异常的问题。给定一个异常对象,将其传递给ExceptionDispatchInfo.Create,它将返回一个ExceptionDispatchInfo对象,其中包含对该异常对象的引用及其详细信息的副本。当抛出异常时,ExceptionDispatchInfo的抛出方法用于恢复异常的内容,并在不丢失原始信息的情况下抛出该异常(当前调用堆栈信息将附加到已存储在异常中的信息中)。
考虑到这一点,再一次选择总是抛出第一个或总是抛出一个聚合,对于“等待”,我们选择总是抛出第一个。然而,这并不意味着您不能访问相同的详细信息。在所有情况下,任务的Exception属性仍然返回一个包含所有异常的AggregateException,因此您可以捕获抛出的任何异常,并在需要时返回咨询Task.Exception。是的,当在“task.Wait()”和“await task”之间切换时,这会导致异常行为之间的差异,但我们认为这是两个坏处中较小的一个。
https://stackoverflow.com/questions/7340309
复制相似问题