简体   繁体   English

处理C#AggregateException的正确方法

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM