[翻译]初试C# 8.0
原文地址:?https://blogs.msdn.microsoft.com/dotnet/2018/12/05/take-c-8-0-for-a-spin/
初試C# 8.0
昨天我們宣布了Visual Studio 2019的第一個預覽版(使用Visual Studio 2019提高每個開發人員的工作效率)和.NET Core 3.0(宣布.NET Core 3預覽1和開源Windows桌面框架)。
其中一個令人興奮的方面是你可以使用C#8.0中的一些功能!在這里,我將帶您進行一次導游,了解您可以在預覽中嘗試的三種新的C#功能。并非所有C#8.0功能都可用。如果您想了解所有主要功能,請閱讀最近發布Building C# 8.0,或查看Channel 9或YouTube。
做好準備
首先,下載并安裝.NET Core 3.0的預覽版1和Visual Studio的2019的預覽版1。在Visual Studio中,確保選擇工作負載“.NET Core跨平臺開發”(如果您忘記了,可以稍后通過打開Visual Studio安裝程序并單擊Visual Studio 2019預覽頻道上的“修改”來添加它)。
啟動Visual Studio 2019預覽版,創建新項目,然后選擇“Console App(.NET Core)”作為項目類型。
項目啟動并運行后,將其目標框架更改為.NET Core 3.0(在解決方案資源管理器中右鍵單擊該項目,選擇“屬性”并使用“應用程序”選項卡上的下拉菜單)。然后選擇C#8.0作為語言版本(在項目頁面的Build選項卡上單擊“Advanced ...”并選擇“C#8.0(beta)”)。
現在,您可以輕松獲得所有語言功能和支持框架類型!
可空的引用類型
可空引用類型功能旨在警告您代碼中的null不安全行為。既然我們之前沒有這樣做過,那么現在就開始改變吧!為避免這種情況,您需要選擇加入該功能。
不過,在我們開啟它之前,讓我們寫一些非常糟糕的代碼:
如果你運行它,你當然會得到一個空引用異常。你陷入了黑洞!你怎么知道不要在特定的地方間接引用s?嗯,因為在前一行分配了null。但是在現實生活中,它可能不是在前一行,而是在你編寫代碼的三年后在地球另一端運行的其他人程序集中。你怎么知道不寫那個?這是可空引用類型要回答的問題!所以讓我們打開它們吧!
對于一個新項目,你應該立即打開它們。事實上,我認為它們應該在新項目中默認啟用,但我們在預覽中沒有這樣做。打開它們的方法是將以下行添加到.csproj文件中,例如在切換到上面的C#8.0時剛剛插入的LanguageVersion之后:
<NullableReferenceTypes>true</NullableReferenceTypes>保存.csproj文件并返回到您的程序:發生了什么?你有兩個警告!每個代表一個功能的“一半”。讓我們依次看看它們。第一個是null這一行:
string s = null;它抱怨你將null賦給“不可空類型”:啥?!?當打開該功能時,在普通的引用類型中不再歡迎使用null,例如string!因為,你知道嗎,null不是一個字符串!我們一直假裝在過去的五十年在面向對象編程,但實際上null并不是一個對象:這就是為什么每當你試圖將它做為對象時一切都會爆炸!
所以不多說:null是禁止的,除非你要求它。你是怎么要求的?通過使用可空的引用類型,例如string?。尾隨問號表示允許null:
string? s = null;警告消失了:我們已明確表達了此變量保持null的意圖,所以現在沒問題了。
直到下一行代碼!在該行:
WriteLine($"The first letter of {s} is {s[0]}");它抱怨s中s[0],你可能會間接引用一空引用。果然:是!干得好,編譯器!你怎么解決它?嗯,這幾乎取決于你 - 無論何種方式你得修復它!讓我們嘗試初學者的方法, 只在s非null時執行該行:
if (s != null) WriteLine($"The first letter of {s} is {s[0]}");警告消失了!為什么?因為編譯器可以看到,只有s不是null時才會走后面的代碼。它實際上進行了全流分析,跟蹤每行代碼中的每個變量,以便密切關注它可能是null的和可能不是的位置。它會監視您的測試和作業,并進行簿記(bookkeeping)。
我們試試另一種方法:
WriteLine($"The first letter of {s} is {s?[0] ?? '?'}");這使用null條件索引運算符s?[0],它避免了間接引用,如果s為null ,則生成null。現在我們有一個可空的char?,但是null合并運算符?? '?'替換null值為字符 '?'。因此避免了所有null間接引用。編譯器很高興,沒有給出警告。
正如您所看到的,該功能可以讓您在編寫代碼時保持誠實:它會強制您在系統中使用null時通過使用可空的引用類型來表達您的意圖。并且一旦出現null,它就會強制您負責任地處理它,讓您在存在可能間接引用null值以觸發空引用異常的風險時進行檢查。
你現在完全null安全了嗎?沒有。有幾種方法可以使null值漏掉并導致空引用異常:
如果你調用沒有可空的引用類型功能的代碼(也許它是在該功能存在之前編譯的),那么我們無法知道該代碼的意圖是什么:它沒有區分可空和不可空 - 我們說它是“無視的”。所以我們給它一個通行證; 我們根本不會對此類調用發出警告。
分析器本身有一些漏洞。其中大多數是安全和便利之間的權衡; 如果我們抱怨,那將很難修復。例如,當你編寫時new string[10],我們創建一個充滿null值的數組,類型為非null字符串。我們不會對此發出警告,因為編譯器如何跟蹤您初始化所有數組元素?
但總的來說,如果你廣泛使用這個功能(即在任何地方打開它),它應該照顧絕大多數的空引用。
毫無疑問地,我們打算在現有代碼上開始使用該功能!一旦打開它,您可能會收到很多警告。其中一些實際上代表了問題:是的,你發現了一個錯誤!其中一些可能有點煩人; 你的代碼顯然是null安全的,你只是沒有工具來表達你的意圖:你沒有可空的引用類型!例如,在我們開始的行:
string s = null;這在現有代碼中將非常普遍!正如你所看到的那樣,我們也確實在下一行發出了警告,我們試圖間接引用它。因此,從安全的角度來看,此處的賦值警告嚴格來說是多余的:它使您在新代碼中保持誠實,但修復現有代碼中的所有事件并不會使其更安全。對于這種情況,我們正在處理一種模式,其中某些警告被關閉,當它不影響空安全性時,因此升級現有代碼不那么令人生畏。
另一個有助于升級的功能是,您可以使用編譯器指令#nullable enable和#nullable disable在代碼中“本地”打開或關閉該功能。這樣你就可以逐步完成你的項目并逐步處理注釋和警告。
要了解更多關于可空引用類型檢查出Overview of Nullable types和Introduction to nullable tutorial。
為了更深入的設計理由,去年我在C#中寫了一篇帖子Introducing Nullable Reference Types in C#。
如果您想讓自己沉浸在設計工作的日常工作中,請查看GitHub上的Language Design Notes,或者Nullable Reference Types Specification。
范圍和索引
使用索引數據結構時,C#的表現力越來越強。曾經想要簡單的語法來切出數組,字符串或span的一部分嗎?現在你可以!
繼續將您的程序更改為以下內容:
讓我們來看看迭代名字數組的那段代碼。修改foreach如下:
foreach (var name in names[1..4])看起來我們正在迭代名字1到4。事實上代碼運行時也確實如此!終點是排外的,即不包括元素4。1..4實際上是一個范圍表達式,它不必像該處一樣,作為索引操作的一部分出現。它有一種自己的類型,叫做Range。如果我們想要的話,我們可以把它拉到自己的變量中,它會起到同樣的作用:
Range range = 1..4; foreach (var name in names[range])范圍表達式的終點不必是整數。事實上,它們屬于一種類型,叫Index,可由非負數轉換得來。但是你也可以使用一個新的^運算符創建Index,意思是“從末尾”。所以^1是從末尾開始1個:
foreach (var name in names[1..^1])這會在數組的每一端去除一個元素,產生一個帶有中間三個元素的數組。
范圍表達式可以在任一端或兩端打開。..^1與0..^1相同。1..與1..^0相同。并且..與0..^0相同:從頭到尾。試試吧!嘗試在Range的兩端混合使用“從開始”和“從末尾”的Index,看看會發生什么。
范圍不僅僅適用于索引器。例如,我們計劃有重載string.SubString,SPan<T>.Slice以及使用Range參數的AsSpan擴展方法。這些不在.NET Core 3.0預覽中。
異步流
IEnumerable<T>在C#中扮演著特殊的角色。“IEnumerables”代表各種不同的數據序列,并且語言具有用于消費和生成它們的特殊構造。
正如我們在當前的程序中看到的那樣,它們通過foreach聲明來消費,該聲明涉及獲取枚舉器的苦差事,反復推進它,沿途提取元素,最后處理枚舉器。并且可以使用迭代器生成它們:yield return按消費者要求產生元素。但兩者都是同步的:當結果被請求時最好已經準備就緒,否則就會阻塞線程!
async和await加入到C#中用來處理當結果被請求時不一定準備好的情況。它們可以異步await,并且線程可以在其可用之前執行其他操作。但這僅適用于單個值,而不適用于隨時間逐漸和異步生成的序列,例如來自IoT傳感器的測量值或來自服務的流數據。
異步流在C#中將異步和枚舉結合在一起!讓我們看看,通過逐步“異步”我們當前的程序。
首先,讓我們在文件的頂部添加另一個using指令:
using System.Threading.Tasks;現在讓我們通過在yield return名字之前增加一個異步延遲來模擬GetNames做了一些異步工作:
await Task.Delay(1000);yield return name;當然,我們得到了一個錯誤: 只能在async方法中使用await。所以我們讓它異步:
static async IEnumerable<string> GetNames()現在我們被告知我們沒有為異步方法返回正確的類型,這是公平的。但除了通常的Task東西之外,這次我們的類型列表中有了一個新的候選可以返回:IAsyncEnumerable
static async IAsyncEnumerable<string> GetNames()就像我們已經生成了一個異步字符串流!根據命名指南,讓我們重命名GetNames為GetNamesAsync。
static async IAsyncEnumerable<string> GetNamesAsync()現在我們在Main方法中的這一行得到一個錯誤:
foreach (var name in GetNamesAsync())不知道如何foreach一個IAsyncEnumerable<T>。這是因為異步流的foreach需要顯式使用await關鍵字:
await foreach (var name in GetNamesAsync())這是foreach的異步版本:采用異步流并等待每個元素!當然它只能在異步方法中這樣做,所以我們必須使我們的Main方法異步。幸運的是,C#7.2增加了對它的支持:
static async Task Main(string[] args)現在所有的混亂都消失了,程序是正確的。但是如果你嘗試編譯并運行它,你會得到一些令人尷尬的錯誤。那是因為我們搞砸了一下,并沒有完全對齊.NET Core 3.0和Visual Studio 2019的預覽。具體來說,有一種實現類型,異步迭代器利用它與編譯器期望的不同。
您可以通過向項目添加單獨的源文件來修復此問題,其中包含此橋接代碼。再次編譯,一切都應該工作得很好。
下一步
請讓我們知道你的想法!如果您嘗試這些功能并了解如何改進它們,請使用Visual Studio 2019預覽中的反饋按鈕。預覽的整個目的是根據現實用戶手中的功能如何進行最后一次校正,所以請告訴我們!
原文地址:https://www.cnblogs.com/waku/p/10094691.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結
以上是生活随笔為你收集整理的[翻译]初试C# 8.0的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【.NET Core项目实战-统一认证平
- 下一篇: .NET Core微服务之路:让我们对上