博主簡單數了下自己發布過的異步文章,已經斷斷續續 8 篇了,這次我想以 async 的返回類型為例,單獨談談。
異步方法具有三個可讓開發人員選擇的返回類型:Task<TResult>、Task 和 void。
什麼時候需要使用哪一種返回類型,具體情況需要具體分析。如果使用不當,程序的執行結果也許並不是你想要的,下面我們就來好好談談如何針對不同的情況選擇不同的返回類型。
【記住】當你添加 async 關鍵字後,需要返回一個將用於後續操作的對象,請使用 Task<TResult>。
Task<TResult> 返回類型可用於 async 方法,其中包含指定類型 TResult
。
在下面的示例中,GetDateTimeAsync 異步方法包含一個返回當前時間的 return 語句。 因此,方法聲明必須指定 Task<DateTime>
。
async Task<DateTime> GetDateTimeAsync() { //Task.FromResult 是一個占位符,類型為 DateTime return await Task.FromResult(DateTime.Now); }
調用 GetDateTimeAsync 方法:
async Task CallAsync() { //在另一個異步方法的調用方式 DateTime now = await GetDateTimeAsync(); }
當 GetDateTimeAsync 從 await 表達式中調用時,await 表達式將檢索存儲在由 GetDateTimeAsync 返回的 task 中的 DateTime 類型值。
async Task CallAsync() { //在另一個異步方法的調用方式 //DateTime now = await GetDateTimeAsync(); //換種方式調用 Task<DateTime> t = GetDateTimeAsync(); DateTime now = await t; }
通過 CallAsync 方法對 GetDateTimeAsync 方法的調用,對非立即等待的方法 GetDateTimeAsync 的調用返回 Task<DateTime>
。 該任務指派給示例中的 DateTime 的 Task
變量。 因為 DateTime 的 Task
變量是 Task<DateTime>,也就是說這裡的 TResult
就是 DateTime 類型。 在這種情況下,TResult 表示日期類型。 當 await
應用於 Task<DateTime>,await 表達式的計算結果為 Task<DateTime> 的 DateTime 類型的內容。同時,該值會分配給 now 變量。
這次我演示不同的變量,你可以自己對比下結果是否相同:
async Task CallAsync() { //在另一個異步方法的調用方式 DateTime now = await GetDateTimeAsync(); //換種方式調用 Task<DateTime> t = GetDateTimeAsync(); DateTime now2 = await t;
//輸出的結果對比 Console.WriteLine($"now: {now}"); Console.WriteLine($"now2: {now2}"); Console.WriteLine($"t.Result: {t.Result}"); }
我這邊可以給出的答案就是:結果是一樣的。
【注意】task 的 Result 屬性為鎖定屬性。如果你在該 task 完成之前嘗試讀取該屬性值,會出現的結果是,當前處於活動狀態的 thread 將被阻塞,阻塞到該 task 完成且結果值為可用時。 在大多數情況下,你都應通過使用 await
訪問屬性值,而不是直接訪問該屬性。
【記住】你如果只是想知道執行的狀態,而不需要知道具體的返回結果時,請使用 Task。
不包含 return 語句,或者說不包含返回值的 return 語句的 async 方法通常具有返回類型 Task。如果這樣的同步方法被編寫為 async 的,這些方法實際上也是返回 void 的方法。 如果在異步方法中使用 Task
返回類型,調用方法可以使用 await 運算符暫停調用方的完成,直至被調用的 async 方法結束。
請看示例:
async Task DelayAsync() { //Task.Delay 是一個占位符,用於假設方法正處於工作狀態。 await Task.Delay(100); Console.WriteLine("OK!"); }
通過使用 await 語句而不是 await 表達式來調用和等待 DelayAsync 方法,類似於返回 void 的方法的調用語句。 await 運算符的應用程序在這種情況下不生成值。
請看調用 DelayAsync 的示例。
//調用和等待方法在同一聲明中 await DelayAsync();
現在,我用將調用和等待的方法進行分離:
//分離 Task delayTask = DelayAsync(); await delayTask;
【記住】如果在觸發後,你不想管了,請使用 void。如事件處理程序。
void 返回類型主要用在事件處理程序中。 void 返回類型還可用來替代不返回任何東西的方法,或者用於執行可分類為"調用後不管了"活動的方法。 但是,你都應盡可能地返回類型 Task
,因為,不能 await 返回類型為 void 的 async 方法。 async 方法的任何調用方只能夠繼續完成(意味著有可能會出現 thread 阻塞),而無需等待調用的 async 方法完成,並且調用方應該,或者說必須獨立於 async 方法生成的任何值或 exception。
返回 void 的 async 方法的調用方無法 catch 從該方法引發的 exception,並且,這種未經處理的 exception 可能會導致你的程序出現難以發現的故障。 如果返回 Task 類型或 Task<TResult> 類型的 async 方法中出現 exception,這種 exception 將存儲於返回的任務中,並將在 await 該任務時再次觸發。也就是說,請盡量優先使用 Task<TResult> 和 Task,這樣,調用方才能從中讀取異常信息,並選擇如何處理。
現在,異常也可以使用 await 了,請移步到這裡 《回眸 C# 的前世今生 - 見證 C# 6.0 的新語法特性》。
void 返回值示例:
private async void button1_Click(object sender, EventArgs e) { //啟動進程並等待完成 await Task.Delay(100); }
當你添加 async 關鍵字後,需要返回一個將用於後續操作的對象,請使用 Task<TResult>;
你如果只是想知道執行的狀態,而不需要知道具體的返回結果時,請使用 Task;
如果在觸發後,你不想管了,請使用 void。
【博主】反骨仔
【出處】http://www.cnblogs.com/liqingwen/p/6218994.html
【參考】微軟官方文檔