2017-08-01 68 views
2

所以我明白爲什麼從異步返回void通常沒有意義,但我遇到了一種情況,我認爲這將是完全有效的。考慮以下人爲的例子:爲什麼無效異步不好?

protected override void OnLoad(EventArgs e) 
{ 
    if (CustomTask == null) 
     // Do not await anything, let OnLoad return. 
     PrimeCustomTask(); 
} 
private TaskCompletionSource<int> CustomTask; 

// I DO NOT care about the return value from this. So why is void bad? 
private async void PrimeCustomTask() 
{ 
    CustomTask = new TaskCompletionSource<int>(); 
    int result = 0; 
    try 
    { 
     // Wait for button click to set the value, but do not block the UI. 
     result = await CustomTask.Task; 
    } 
    catch 
    { 
     // Handle exceptions 
    } 
    CustomTask = null; 

    // Show the value 
    MessageBox.Show(result.ToString()); 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
    if (CustomTask != null) 
     CustomTask.SetResult(500); 
} 

我意識到這是一個不尋常的例子,但我試圖使它簡單和更一般化。有人可以向我解釋爲什麼這是可怕的代碼,以及我如何修改它以正確遵循約定?

感謝您的任何幫助。

+1

閱讀此項。 https://msdn.microsoft.com/en-us/magazine/jj991977.aspx – Nkosi

+0

@Nkosi我明白爲什麼這是一個不好的做法,但爲什麼我的代碼特別是這些不良做法的症狀?如果不使用void async,我該怎麼做呢? – AnotherProgrammer

+0

@Nkosi該死的我不知道 –

回答

4

使用無效的異步只有一般看作是「壞」爲:

  • 你不能等待它完成後(如在這篇文章中所提到的話)
  • 任何未處理的異常將終止您的(ouch!)

有很多情況下(如你的)使用它的情況很好。使用時請謹慎。

7

好,穿行在"avoid async void" article的原因:

  • 異步void的方法有不同的錯誤處理語義。從PrimeCustomTask轉義出來的例外情況將會非常尷尬。
  • 異步無效方法具有不同的組合語義。這是圍繞代碼可維護性和重用性的論點。本質上,PrimeCustomTask中的邏輯就在那裏,就是這樣 - 它不能組成更高級別的方法async
  • 異步無效方法很難測試。從前兩點自然而然,編寫一個涵蓋PrimeCustomTask(或稱之爲任何東西)的單元測試是非常困難的。

重要的是要注意async Task是自然的方法。在several languages that have adopted async/await中,C#/ VB是唯一支持async void的AFAIK。 F#不會,Python不會,JavaScript和TypeScript不會。從語言設計的角度來看,async void是不自然的。

原因async void被添加到C#/ VB是爲了啓用異步事件處理程序。如果你改變你的代碼使用async void事件處理程序:

protected override async void OnLoad(EventArgs e) 
{ 
    if (CustomTask == null) 
    await PrimeCustomTask(); 
} 

private async Task PrimeCustomTask() 

然後async void缺點限制在事件處理程序。特別是,來自PrimeCustomTask的異常自然傳播到它的(異步)調用者(OnLoad),可以編寫PrimeCustomTask(從其他異步方法自然調用),並且PrimeCustomTask更容易包含在單元測試中。