博主簡單數了下本身發佈過的異步文章,已經斷斷續續 8 篇了,此次我想以 async 的返回類型爲例,單獨談談。html
異步方法具備三個可以讓開發人員選擇的返回類型:Task<TResult>、Task 和 void。 編程
何時須要使用哪種返回類型,具體狀況須要具體分析。若是使用不當,程序的執行結果也許並非你想要的,下面咱們就來好好談談如何針對不一樣的狀況選擇不一樣的返回類型。異步
【記住】當你添加 async 關鍵字後,須要返回一個將用於後續操做的對象,請使用 Task<TResult>。async
Task<TResult> 返回類型可用於 async 方法,其中包含指定類型 TResult
。ide
在下面的示例中,GetDateTimeAsync 異步方法包含一個返回當前時間的 return 語句。 所以,方法聲明必須指定 Task<DateTime>
。異步編程
async Task<DateTime> GetDateTimeAsync() { //Task.FromResult 是一個佔位符,類型爲 DateTime return await Task.FromResult(DateTime.Now); }
調用 GetDateTimeAsync 方法:post
async Task CallAsync() { //在另外一個異步方法的調用方式 DateTime now = await GetDateTimeAsync(); }
當 GetDateTimeAsync 從 await 表達式中調用時,await 表達式將檢索存儲在由 GetDateTimeAsync 返回的 task 中的 DateTime 類型值。 ui
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 變量。url
此次我演示不一樣的變量,你能夠本身對比下結果是否相同:spa
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}"); }
我這邊能夠給出的答案就是:結果是同樣的。
【注意】主要有兩種方式獲取結果值,一個是使用 Result 屬性,一個是使用 await。他們的區別在於:若是你使用的是 Result,它帶有阻塞性。即在任務完成以前進行訪問讀取它,當前處於活動狀態的線程都會出現阻塞的情形,一直到結果值可用。因此,在絕大多數狀況下,除非你有絕對的理由告訴本身,不然都應該使用 await,而不是屬性 Result 來讀取結果值。
【記住】你若是隻是想知道執行的狀態,而不須要一個具體的返回結果時,請使用 Task。
一個返回類型爲 Task 類型的異步方法,它的具體實現不該該包含 return 語句,或者說是一個 return void 的語句。這個 Task 類型是不包含屬性 Result 的。跟 Task<TResult> 調用同樣,調用方法直接使用 await 掛起並等待異步方法的執行完畢。
請看示例:
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 返回類型主要用在事件處理程序中,一種稱爲「fire and forget」(觸發並忘記)的活動的方法。除了它以外,咱們都應該儘量是用 Task,做爲咱們異步方法的返回值。
返回 void,意味着不能 await 該異步方法,便可能出現線程阻塞,而且也沒法獲取 exception,拋出的異常,一般這些異常會致使咱們的程序失敗,若是你使用的是 Task 和 Task<Result>,catch 到的異常會包裝在屬性裏面,調用方法就能夠從中獲取異常信息,並選擇正確的處理方式。
如今,異常也可使用 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
【參考】https://docs.microsoft.com/en-us/dotnet/articles/csharp/programming-guide/concepts/async/async-return-types
【參考】微軟官方文檔