翻譯|使用教程|編輯:吳園園|2019-10-21 10:04:16.260|閱讀 395 次
概述:本文將為您帶來異步流– C#8中的新語言功能介紹。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
ReSharper是一個著名的代碼生成工具,其能幫助Microsoft Visual Studio成為一個更佳的IDE。實質上,ReSharper特征可用于C#,VB.net,XML,Asp.net,XAML,和構建腳本。
ReSharper Ultimate 2019.2提供了對C#8.0的更好支持以及一些Navigation,Find Usages和調試器數據提示的更新。它還改善了啟動時間,并為VS 2019中的“Per-Monitor DPI Awareness”模式提供了初始支持.C ++項目的索引更快,支持更多C ++ 20功能。點擊查看更新詳情!
自從C#8系列的最后一部分以來已經有一段時間了,但是它來了!我們將繼續通過新的語言功能進行探索,并深入到異步流中。
在本系列中,我們正在研究:
指數,范圍和空值分配
切換表達式和基于模式的用法
遞歸模式匹配
異步流
異步編程是一種編程形式,它可以通過允許將耗時的工作(例如從網絡下載數據)與主線程分離來防止阻塞我們的應用程序。對于我們的實現,原則上,它需要將回調傳遞給異步方法,該異步方法又會在完成工作后調用該回調。
在C#5中,引入了async和await關鍵字。這些從根本上改善了我們編寫和使用異步方法的方式。基本上,與同步實現相比,我們的代碼結構可以保持幾乎相同,但是編譯器接管了很多工作,將我們的代碼重組為上述回調,以使其具有狀態且無阻塞。但是,這僅適用于使用Task和Task<T>作為返回類型的void和單結果方法。
產生數據流的方法(又名IEnumerable<T>)被省去了,需要編寫自定義代碼。但是,此類要求非常普遍,例如考慮使用云應用程序,從IoT傳感器收集數據或從數據庫接收數據。,C#8和IAsyncEnumerable!
隨著.NET 2.1標準的發布,引入了一組3個接口: IAsyncDisposable,IAsyncEnumerable<T>和IAsyncEnumerator<T>。這些接口允許我們以某種方式表示的異步版本IEnumerable<T>,從而使用異步流:
public interface IAsyncDisposable { ValueTask DisposeAsync(); } public interface IAsyncEnumerable<out T> { IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken token = default); } public interface IAsyncEnumerator<out T> : IAsyncDisposable { ValueTask<bool> MoveNextAsync(); T Current { get; } }
為了IAsyncEnumerable<T>在各種情況下都能正常工作(如await在finally塊中一樣),我們還需要IDisposable接口的異步版本。您可能已經猜到了,它叫做IAsyncDisposable:
public interface IAsyncDisposable { ValueTask DisposeAsync(); }
從.NET Core SDK 3.0開始,實際上已經實現了這些類型,并且使用C#8 foreach,using可以將and 關鍵字作為前綴await與IAsyncEnumerableand IAsyncDisposable實例一起使用。
IAsyncEnumerable<T>實質上,迭代意味著獲取下一個對象成為異步操作,而foreach主體成為我們的回調。只有當我們繼續循環時,才會提取一個新項目(與調用相對break)。這基本上將這種方法標記為基于拉的方法。該await foreach語句還基于模式工作,這意味著它將與提供適當GetAsyncEnumerator方法但不實現IAsyncEnumerable<T>接口的任何類型一起工作。
讓我們看看如何將這些添加項組合使用。好奇的開發人員絕對應該抓住機會,看看它的反編譯代碼:
static async Task Main() { await foreach (var data in ReadAndNormalize()) { Console.WriteLine(data); } } static async IAsyncEnumerable<Data> ReadAndNormalize( [EnumeratorCancellation] CancellationToken token = default) { while (!token.IsCancellationRequested) { var data = await ReadInputFromDevice(); var normalizedData = ConvertAndNormalize(data); yield return normalizedData; } } static async Task<byte[]> ReadInputFromDevice() { return default; } static Data ConvertAndNormalize(byte[] data) { return default; } struct Data { }
請注意,CancellationToken標記有一個EnumeratorCancellation屬性。與JetBrains.Annotations包中的EnumeratorCancellation屬性相似,該屬性(包含在中System.Runtime.CompilerServices)將代碼片段標記為其他魔術,這些魔術目前還無法用語言本身來表達。
如前所述,using語句現在也可以使用await關鍵字作為前綴。讓我們一起來看看!
async Task WriteToFileAsync(string file) { await using (var fs = new FileStream(file, FileMode.CreateNew)) await using (var sw = new StreamWriter(fs)) { await sw.WriteAsync("Hello C#8!"); } }
由于.NET標準2.1,兩個所涉及的類型FileStream,并StreamWriter都實現IAsyncDisposable。這樣就可以異步完成所有處理工作,例如刷新磁盤更改。
ReSharper和Rider能為我做什么?
除了解析新的語言結構外,ReSharper和Rider還帶來了其他一些有助于異步流工作的優點。
從我們可以枚舉的最明顯的操作開始,foreach 后綴模板已更新為完成,await foreach直到有問題的枚舉類型為IAsyncEnumerable<T>或匹配其模式:
在最后一個示例中,我們犯了一個錯誤。我們沒有通過取消令牌!幸運的是,這里進行了新的代碼檢查,并提供了一個快速修復程序來使事情正確:
等等,還有另一個棘手的示例,其中ReSharper和Rider將注意到可以使用WithCancellation擴展方法傳遞取消令牌。還記得EnumeratorCancellation我們提到的屬性嗎?這將允許編譯器用與原始令牌組合的有效取消令牌替換取消令牌的每種用法IAsyncEnumerator:
每當我們想要返回an IAsyncEnumerable<T>但該方法尚未標記時async,ReSharper和Rider都會建議從方法名稱區域或從await出現的關鍵字中返回:
同樣,當我們使用已標記為的方法時async,ReSharper和Rider將允許從錯誤定義的IEnumerable<T>返回類型更改為IAsyncEnumerable<T>:
在消費方面,另一種快速修復方法是將同步foreach語句更改為異步await foreach語句。在轉換現有代碼以利用新的語言功能時,這可能很有用:
最后但并非最不重要的一點,讓我們回到IAsyncDisposable并等待使用。如果方法是async,并且所討論的對象實現了異步對象DisposeAsync,則Rider和ReSharper將顯示檢查結果,await using可以代替使用。同樣,我們可以將await using語句轉換為基于模式的using中描述的聲明。相應的快速修復可以在范圍內應用:
=====================================================
想要了解或購買ReSharper正版授權的朋友,歡迎
關注下方“慧聚IT”微信公眾號,及時獲取產品最新消息和最新資訊
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自: