c# – 处理来自异步并行任务的多个异常

前端之家收集整理的这篇文章主要介绍了c# – 处理来自异步并行任务的多个异常前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
问题

有几个任务是并行运行的,all,none或者其中任何一个都可能抛出异常.当所有任务完成后,必须报告所有可能发生的异常(通过日志,电子邮件,控制台输出……等等).

预期的行为

我可以使用asq lambdas通过linq构建所有任务,然后等待它们与Task.WhenAll(任务)并行运行.然后我可以捕获AggregateException并报告每个单独的内部异常.

实际行为

抛出了AggregateException,但它只包含一个内部异常,无论抛出多少个别异常.

最小的完整可验证的例子

static void Main(string[] args)
{
    try
    {
        ThrowSeveralExceptionsAsync(5).Wait();
    }
    catch (AggregateException ex)
    {
        ex.Handle(innerEx =>
        {
            Console.WriteLine($"\"{innerEx.Message}\" was thrown");
            return true;
        });
    }

    Console.ReadLine();
}

private static async Task ThrowSeveralExceptionsAsync(int nExceptions)
{
    var tasks = Enumerable.Range(0,nExceptions)
        .Select(async n =>
        {
            await ThrowAsync(new Exception($"Exception #{n}"));
        });

    await Task.WhenAll(tasks);
}

private static async Task ThrowAsync(Exception ex)
{
    await Task.Run(() => {
        Console.WriteLine($"I am going to throw \"{ex.Message}\"");
        throw ex;
    });
}

产量

请注意,由于竞争条件,“我要投掷”消息的输出顺序可能会发生变化.

I am going to throw "Exception #0"
I am going to throw "Exception #1"
I am going to throw "Exception #2"
I am going to throw "Exception #3"
I am going to throw "Exception #4"
"Exception #0" was thrown

解决方法

那是因为等待“解包”聚合异常并且总是抛出第一个异常(如 await的文档中所述),即使等待Task.WhenAll显然会导致多个错误.您可以访问聚合异常,例如:
var whenAll = Task.WhenAll(tasks);
try {
    await whenAll;
}
catch  {
    // this is `AggregateException`
    throw whenAll.Exception;
}

或者你可以循环遍历任务并检查每个任务的状态和异常.

请注意,在修复之后,您还需要做一件事:

try {
    ThrowSeveralExceptionsAsync(5).Wait();
}
catch (AggregateException ex) {
    // flatten,unwrapping all inner aggregate exceptions
    ex.Flatten().Handle(innerEx => {
        Console.WriteLine($"\"{innerEx.Message}\" was thrown");
        return true;
    });
}

因为ThrowSeveralExceptionsAsync返回的任务包含我们抛出的AggregateException,包含在另一个AggregateException中.

原文链接:https://www.f2er.com/csharp/97664.html

猜你在找的C#相关文章