等待多个任务将观察到比第一个异常更多的情况

本文关键字:异常 第一个 情况 任务 观察 等待 | 更新日期: 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(如下面的示例所示(,但在这两种情况下,ab 都不会引发UnobservedTaskException

var task = Task.WhenAll(a, b);
try
{
    await task;
}
catch
{
    Trace.WriteLine(string.Join(", ", task.Exception.Flatten().InnerExceptions.Select(e => e.Message)));
}