博主簡單數了下本身發佈過的異步文章,已經斷斷續續 8 篇了,此次我想以 async 的返回類型爲例,單獨談談。html
異步方法具備三個可以讓開發人員選擇的返回類型:Task<TResult>、Task 和 void。 異步
何時須要使用哪種返回類型,具體狀況須要具體分析。若是使用不當,程序的執行結果也許並非你想要的,下面咱們就來好好談談如何針對不一樣的狀況選擇不一樣的返回類型。async
【記住】當你添加 async 關鍵字後,須要返回一個將用於後續操做的對象,請使用 Task<TResult>。post
Task<TResult> 返回類型可用於 async 方法,其中包含指定類型 TResult
。url
在下面的示例中,GetDateTimeAsync 異步方法包含一個返回當前時間的 return 語句。 所以,方法聲明必須指定 Task<DateTime>
。spa
async Task<DateTime> GetDateTimeAsync() { //Task.FromResult 是一個佔位符,類型爲 DateTime return await Task.FromResult(DateTime.Now); }
調用 GetDateTimeAsync 方法:code
async Task CallAsync() { //在另外一個異步方法的調用方式 DateTime now = await GetDateTimeAsync(); }
當 GetDateTimeAsync 從 await 表達式中調用時,await 表達式將檢索存儲在由 GetDateTimeAsync 返回的 task 中的 DateTime 類型值。 htm
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 變量。對象
此次我演示不一樣的變量,你能夠本身對比下結果是否相同:blog
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。