15.3 Task 語法和語義
阿新 • • 發佈:2018-12-15
15.3.1 宣告非同步方法和返回型別
1 async static void GetStringAsync() 2 { 3 using (var client = new HttpClient()) 4 { 5 Task<string> task = client.GetStringAsync("https://www.baidu.com/"); 6 string result = await task; 7 }8 }
15.3.3 可等待模式
大量工作都是通過模式來表示的,這有點類似於 foreach 和LINQ查詢。為了更清晰地描述
該模式的輪廓,假設存在一些相關的介面(但實際並沒有)。稍後我會介紹真實情況,現在先來
看看虛構的介面:
1 /// <summary> 為包含返回值的非同步操作 建立的虛擬的介面 警告:這些並不存在 自定義的</summary> 2 public interface IAwaitable<T> 3 { 4 IAwaiter<T> GetAwaiter();5 } 6 7 public interface IAwaiter<T> : INotifyCompletion 8 { 9 bool IsCompleted { get; } 10 T GetResult(); 11 12 //從INotifyCompletion 繼承 13 //void OnCompleted(Action continuation); 14 } 15 16 /// <summary> 為沒有返回值的非同步操作 建立的虛擬的介面</summary> 17 public interface IAwaitable 18 { 19 IAwaiter GEtAwaiter(); 20 } 21 22 public interface IAwaiter : INotifyCompletion 23 { 24 bool IsCompleted { get; } 25 void GetResult(); 26 27 //從INotifyCompletion 繼承 28 //void OnCompleted(Action continuation); 29 }
前面講述了什麼樣的表示式可以作為 await 關鍵字的目標,不過整個表示式本身也同樣擁有
一個有趣的型別:如果 GetResult() 返回 void ,那麼整個 await 表示式就沒有型別,而只是一
個獨立的語句。否則,其型別與 GetResult() 的返回型別相同。
例如, Task<TResult>.GetAwaiter() 返回一個 TaskAwaiter<TResult> ,其 GetResult()
方法返回 TResult 。(希望你不會感到奇怪。)根據 await 表示式的型別規則,我們可以編寫這樣
的程式碼:
1 using (var client = new HttpClient()) 2 { 3 Task<string> task = client.GetStringAsync("https://www.baidu.com/"); 4 string result = await task; 5 }
這裡的 await 表示式不會返回任何型別的值,因此不能將其分配給變數,或作為方法實參進
行傳遞,也不能執行其他任何將表示式作為值的相關操作。
需要注意的是,由於 Task 和 Task<TResult> 都實現了可等待模式,因此可以在一個非同步方
法內呼叫另一個非同步方法:
1 public async Task<int> Foo() 2 { 3 string bar = await BarAsync(); 4 //顯然通常會更復雜 5 return bar.Length; 6 } 7 public async Task<string > BarAsync() 8 { 9 //一些非同步程式碼,可能會呼叫更多非同步方法 10 }
組合非同步操作正是非同步特性大放異彩的一個方面。進入非同步模式(mode)後,就可以很輕
鬆地保持這種模式,編寫自然流暢的程式碼。