簡體   English   中英

處理C#AggregateException的正確方法

[英]Proper way to handle C# AggregateException

我有一個關於何時使用WhenAll()處理聚合異常的安全性的問題。 看起來自然的位置會在catch塊內,因為如果catch塊永遠不會觸發,那就意味着沒有異常可以處理。 但我看到很多代碼都有一個空的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() {
      // ...
    }

似乎自然的地方將在捕獲區內

是的,那會很好。 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);
    }
  }

你當然可以這樣做。 基本上它是一樣的。 使用在特定情況下更方便的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM