等待多个任务将观察到比第一个异常更多的情况
本文关键字:异常 第一个 情况 任务 观察 等待 | 更新日期: 2023-09-27 18:22:47
今天,我和我的同事讨论了如何在 C# 5.0 async
方法中正确处理异常,我们想知道一次等待多个任务是否也会观察到运行时未解包的异常。
请考虑以下代码片段:
async Task ExceptionMethodAsync()
{
await Task.Yield();
throw new Exception();
}
async Task CallingMethod()
{
try
{
var a = ExceptionMethodAsync();
var b = ExceptionMethodAsync();
await Task.WhenAll(a, b);
}
catch(Exception ex)
{
// Catches the "first" exception thrown (whatever "first" means)
}
}
现在第二个任务会发生什么?两者都将处于故障状态,但现在是观察到还是未观察到第二个任务的异常?
Task.WhenAll
返回一个任务,与所有任务一样,Exception
属性包含一个组合所有异常的AggregateException
。
当您await
此类任务时,实际上只会引发第一个异常。
。无论是因为子任务出错,还是因为像 Task.WhenAlll 这样的组合器,单个任务可能表示多个操作,并且其中多个操作可能会出错。 在这种情况下,为了不丢失异常信息(这对于事后调试可能很重要(,我们希望能够表示多个异常,因此对于包装器类型,我们选择了 AggregateException。
。鉴于此,再次可以选择总是抛出第一个或总是抛出一个聚合,对于"等待",我们选择总是抛出第一个
来自 .NET 4.5 中的任务异常处理
由您选择是只想处理第一个使用 await task;
(在大多数情况下为 true(还是处理所有使用 task.Exception
(如下面的示例所示(,但在这两种情况下,a
和 b
都不会引发UnobservedTaskException
。
var task = Task.WhenAll(a, b);
try
{
await task;
}
catch
{
Trace.WriteLine(string.Join(", ", task.Exception.Flatten().InnerExceptions.Select(e => e.Message)));
}