[英]Proper way to handle C# AggregateException
I have a question about when its safe to handle an aggregate exception when using WhenAll(). 我有一个关于何时使用WhenAll()处理聚合异常的安全性的问题。 It seems like the natural place would be inside the catch block, because if the catch block never fires, it would imply there are no exceptions to handle.
看起来自然的位置会在catch块内,因为如果catch块永远不会触发,那就意味着没有异常可以处理。 But I see a lot of code that has an empty catch block and checks for the existence of an AggregateException before handling any found exceptions (including on MS website).
但我看到很多代码都有一个空的catch块,并在处理任何找到的异常(包括在MS网站上)之前检查是否存在AggregateException。
public async Task MyMethod() {
var tasks = new List<Task>();
for (var i = 0; i < 10; i++) {
tasks.Add(DoSthAsync());
}
var masterTask = Task.WhenAll(tasks);
try {
var results = await masterTask;
} catch {
// Safe to access masterTask here and handle aggregate exceptions? Have all tasks completed?
foreach (var ex in masterTask.Exception.innerExceptions) {
HandleException(ex);
}
}
// Or necessary to check for and handle aggregate exceptions here?
if (masterTask.Exception != null) {
foreach (var ex in masterTask.Exception.innerExceptions) {
HandleException(ex);
}
}
}
public async Task DoSthAsync() {
// ...
}
It seems like the natural place would be inside the catch block
似乎自然的地方将在捕获区内
Yup, that would work fine. 是的,那会很好。
Task.WhenAll
returns a task that completes when all the tasks have completed. Task.WhenAll
返回在所有任务完成后完成的任务。 So in your case, by the time your code enters the catch
block, masterTask
has completed, and this means all the tasks
have completed. 因此,在您的情况下,当您的代码进入
catch
块时, masterTask
已完成,这意味着所有tasks
都已完成。
The code that you posted works because Task.WhenAll
returns a task that only completes when all sub tasks have completed. 您发布的代码有效,因为
Task.WhenAll
返回的任务仅在所有子任务完成后才完成。
Why does the code do it that way? 为什么代码这样做? Why no
catch (Exception ex)
? 为什么没有
catch (Exception ex)
? This is because await only throws the first inner exception. 这是因为等待只抛出第一个内部异常。 If you need access to multiple exceptions this code pattern is a good way to do it.
如果您需要访问多个异常,则此代码模式是一种很好的方法。 You also could do
catch (AggregateException ex)
and use that object. 您也可以执行
catch (AggregateException ex)
并使用该对象。 It's the same object. 这是同一个对象。
I personally avoid using catch
like that. 我个人避免使用这样的
catch
。 Essentially it's using exceptions for control flow. 基本上它使用控制流的异常。 This makes debugging harder and can lead to verbose code.
这使得调试更加困难并且可能导致冗长的代码。
I like this: 我喜欢这个:
var whenAllTask = Task.WhenAll(...);
await whenAllTask.ContinueWith(_ => { }); //never throws
if (whenAllTask.Exception != null) ... //handle exceptions
I made the .ContinueWith(_ => { })
bit into a WhenCompleted
extension method so that the code looks clean. 我将
.ContinueWith(_ => { })
位转换为WhenCompleted
扩展方法,以使代码看起来干净。
Then you wondered whether the second way to check for exceptions is a good idea: 然后你想知道检查异常的第二种方法是否是一个好主意:
// Or necessary to check for and handle aggregate exceptions here?
if (masterTask.Exception != null) {
foreach (var ex in masterTask.Exception.innerExceptions) {
HandleException(ex);
}
}
You can certainly do that. 你当然可以这样做。 Essentially it's the same thing.
基本上它是一样的。 Use what is more convenient in the particular situation.
使用在特定情况下更方便的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.