避免非同步無效

  • 唯一可以安全使用 async void 的地方是事件處理程式。請考慮以下程式碼:

    private async Task<bool> SomeFuncAsync() {
      ...
      await ...
    }
    public void button1_Click(object sender,  EventArgs e) {
      var result = SomeFuncAsync().Result;
      SomeOtherFunc();
    }
    

    一旦 async 呼叫完成,它將等待 SynchronizationContext 變為可用。但是,事件處理程式在等待 SomeFuncAsync 方法完成時保持 SynchronizationContext; 從而導致迴圈等待(死鎖)。

    要解決這個問題,我們需要將事件處理程式修改為:

    public async void button1_Click(object sender,  EventArgs e) {
      var result = await SomeFuncAsync();
      SomeOtherFunc();
    }
    
  • 任何從 async void 方法丟擲的異常將直接在 async void 方法啟動時啟用的 SynchronizationContext 上引發。

    private async void SomeFuncAsync() {
      throw new InvalidOperationException();
    }
    public void SomeOtherFunc() {
      try {
        SomeFuncAsync();
      }
      catch (Exception ex) {
        Console.WriteLine(ex);
        throw;
      }
    }
    

    這個例外永遠不會被 SomeOtherFunc 中的 catch 塊捕獲。

  • async void 方法沒有提供一種簡單的方法來通知他們已經完成的呼叫程式碼

  • async void 方法很難測試。MSTest 非同步測試支援僅適用於返回 TaskTask<T>async 方法。