正确处理C#gentregateException的方法



我有一个问题,即当使用时何时安全处理聚合异常。似乎自然的位置将在渔获块内部,因为如果口气块永远不会开火,那就意味着没有例外。但是我看到很多代码具有空的捕获块,并在处理任何发现的异常之前(包括在MS网站上(之前检查了存在聚合exception的存在。


    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() {
      // ...
    }

似乎自然的位置将在渔获块内部

是的,这会很好。Task.WhenAll返回一个任务完成后完成的任务。因此,在您的情况下,当您的代码进入catch块时,masterTask已经完成,这意味着所有tasks都已完成。

您发布的代码工作是因为Task.WhenAll返回仅在所有子任务完成时完成的任务。

为什么代码这样做?为什么没有catch (Exception ex)?这是因为等待仅引发第一个内部异常。如果您需要访问多个异常,则此代码模式是这样做的好方法。您还可以执行catch (AggregateException ex)并使用该对象。这是同一对象。


我个人避免使用catch。从本质上讲,它正在使用控制流的例外。这使调试变得更加困难,并且可能导致详细的代码。

我喜欢:

var whenAllTask = Task.WhenAll(...);
await whenAllTask.ContinueWith(_ => { }); //never throws
if (whenAllTask.Exception != null) ... //handle exceptions

我将.ContinueWith(_ => { })位用于WhenCompleted扩展方法,以使代码看起来很干净。


然后,您想知道检查例外的第二种方法是一个好主意:

  // Or necessary to check for and handle aggregate exceptions here?
  if (masterTask.Exception != null) {
    foreach (var ex in masterTask.Exception.innerExceptions) {
      HandleException(ex);
    }
  }

您当然可以这样做。本质上是同一件事。在特定情况下使用更方便的东西。

相关内容

最新更新