C# 8.0 添加和增強的功能【基礎篇】( 三 )


此外,不能向不可為空引用類型分配一個可以為 Null 的值 。
編譯器使用流分析,來確??蔀榭找妙愋偷娜魏巫兞?,在被訪問或分配給不可為空引用類型之前,都會對其 Null 性進行檢查 。
八、異步流異步流,可針對流式處理數據源建模。數據流經常異步檢索或生成元素,因此它們為異步流式處理數據源提供了自然編程模型 。
// 異步枚舉 , 核心對象是:IAsyncEnumerable[HttpGet("syncsale")]public async IAsyncEnumerable<Product> GetOnSaleProducts(){var products = _repository.GetProducts();await foreach (var product in products) // 消費異步枚舉,順序取決于 IAsyncEnumerator 算法{if (product.IsOnSale)yield return product;// 持續異步逐個返回,不用等全部完成}}另一個實例:模擬異步抓取 html 數據
// 這是一個【相互獨立的長耗時行為的集合(假設分別耗時 5,4,3,2,1s)】static async Task Main(string[] args){Console.WriteLine(DateTime.Now + $"\tThreadId:{Thread.CurrentThread.ManagedThreadId}\r\n");await foreach (var html in FetchAllHtml()) // 默認按照任務加入的順序輸出{Console.WriteLine(DateTime.Now + $"\tThreadId:{Thread.CurrentThread.ManagedThreadId}\t" + $"\toutput:{html}");}Console.WriteLine("\r\n" + DateTime.Now + $"\tThreadId:{Thread.CurrentThread.ManagedThreadId}\t");Console.ReadKey(); } // 這里已經默認實現了一個 IEnumerator 枚舉器: 以 for 循環加入異步任務的順序 static async IAsyncEnumerable<string> FetchAllHtml() {for (int i = 5; i >= 1; i--){var html = await Task.Delay(i* 1000).ContinueWith((t,i)=> $"html{i}",i); // 模擬長耗時yield return html;} }??

C# 8.0 添加和增強的功能【基礎篇】

文章插圖
接著,其實五個操作是分別開始執行的,那么當耗時短的任務處理好后 , 能否直接輸出呢?這樣的話交互體驗就更好了!
static async IAsyncEnumerable<string> FetchAllHtml(){var tasklist= new List<Task<string>>();for (int i = 5; i >= 1; i--){var t= Task.Delay(i* 1000).ContinueWith((t,i)=>$"html{i}",i);// 模擬長耗時任務tasklist.Add(t);}while(tasklist.Any())// 監控已完成的操作,立即處理{var tFinlish = await Task.WhenAny(tasklist);tasklist.Remove(tFinlish);yield return await tFinlish; // 完成即輸出}}以上總耗時取決于 耗時最長的那個異步任務5s 。
??
C# 8.0 添加和增強的功能【基礎篇】

文章插圖
??參考自:C# 8.0 寶藏好物 Async streams
九、異步可釋放(IAsyncDisposable)IAsyncDisposable 接口,提供一種用于異步釋放非托管資源的機制 。與之對應的就是提供同步釋放非托管資源機制的接口 IDisposable 。
提供此類及時釋放機制,可使用戶執行資源密集型釋放操作,從而無需長時間占用 GUI 應用程序的主線程 。
同時更好的完善.NET異步編程的體驗,IAsyncDisposable誕生了 。它的用法與IDisposable非常的類似:
public class ExampleClass : IAsyncDisposable{ private Stream _memoryStream = new MemoryStream(); public ExampleClass() { } public async ValueTask DisposeAsync() {await _memoryStream.DisposeAsync(); }}// using 語法糖await using var s = new ExampleClass(){ // doing};// 優化 同樣是對象 s 只存在于當前代碼塊await using var s = new ExampleClass();// doing??參考于:熟悉而陌生的新朋友——IAsyncDisposable
十、索引和范圍索引和范圍,為訪問序列中的單個元素或范圍,提供了簡潔的語法 。
新增了兩個類型(System.Index & System.Range)和運算符(末尾運算符"^" & 范圍運算符“..”) 。
用例子說話吧:
var words = new string[]{// index from startindex from end"The",// 0^9"quick",// 1^8"brown",// 2^7"fox",// 3^6"jumped",// 4^5"over",// 5^4"the",// 6^3"lazy",// 7^2"dog"http:// 8^1};// 9 (or words.Length) ^0運算實例:
Console.WriteLine($"The last word is {words[^1]}");// “dog” // 使用 ^1 索引檢索最后一個詞var quickBrownFox = words[1..4];//“quick”、“brown”、“fox” 子范圍var lazyDog = words[^2..^0];// “lazy”、“dog” 子范圍var allWords = words[..];// “The”、“dog”子范圍var firstPhrase = words[..4];// “The”、“fox”子范圍var lastPhrase = words[6..];// “the”、“lazy”、“dog”子范圍另外可將范圍聲明為變量:
Range phrase = 1..4;var text = words[phrase];十一、 Null 合并賦值Null 合并賦值運算符:??=
僅當左操作數計算為 null 時,才能使用運算符 ??= 將其右操作數的值分配給左操作數 。

推薦閱讀