Visual Studio 2019 preview中體驗C# 8.0新語法

準備工做: html

Visual Studio 2019 Preview版本中並無包含全部的C# 8.0的新功能,但目前也有一些能夠試用了。在開始以前,須要進行入兩項設置:git

  1. 將Framework設置爲.net core 3.0
  2. 將C#語法設置爲8.0

也能夠直接編輯.csproj文件,修改TargetFramework和LangVersion爲以下形式:程序員

     <TargetFramework>netcoreapp3.0</TargetFramework>
     <LangVersion>8.0</LangVersion>
github

 

Nullable reference types 編程

空引用對於全部編程者來講相信都是一個很是頭痛的問題,圖靈獎得主Tony Hoare 就把包含空引用的編程語言用定義爲一個十億美圓的錯誤Null References: The Billion Dollar Mistakec#

首先仍是來一段簡單的代碼: 數組

     string s = null;
     Console.WriteLine($"The first letter of {s} is {s[0]}");
app

這段代碼編譯沒有問題,但運行的時候會拋空引用異常的。 異步

在C# 8.0中,開啓了空引用異常檢測後,上述代碼在編譯器就會檢查出告警來。 socket

    

    

而且它會結合上下文判斷,若是該值不會爲null,則不會告警,很是智能。

    

細心的朋友可能會發現,雖然在下面使用的地方沒有告警,可是變量初始化的地方仍是報告警了。若是咱們的程序自己就是容許null值改怎麼辦呢,聽任告警無論也是不合適的作法。

針對這個問題,C#引入了一個新的聲明爲可空對象的語法:

     string? s = null;

也就是在類型後加一個?符號,表面該對象是一個可空對象。

因爲這個行爲和以前的C#版本是不一致的,所以默認是沒有開啓這個功能的,咱們須要在csproj文件中打開這個設置:

     <LangVersion>8.0</LangVersion>
     <NullableReferenceTypes>true</NullableReferenceTypes>

不知道在後續的VS的版本中會不會直接再界面上添加這一設置。

最後總結一下,Nullable reference types主要乾了兩件事:

  1. 能夠經過對象聲明判斷該對象是否可能爲空。
  2. 當可空對象使用在不可空的場景是,會報告警。

雖然以前有一些第三方插件也集成了相似的功能,如Resharper的Null Check,但把這個功能集成到了編譯器上後更加簡潔好用。

C#的空對象檢查在設計期間也有好幾種語法方案,目前這種方案既解決了問題,又對現有代碼保持徹底兼容,還能對現有代碼潛在性問題能進行分析,是一種比較理想的方案的。若是之後能經過設置,將空引用的告警級別能夠設置爲錯誤就更好了。

 

Ranges and indices

範圍和索引是C#新引入的語法,它主要引入了兩個對象Range和Index。

Index

首先仍是來看一個簡單的例子。

     var numbers = new[] { 1, 2, 3, 4, 5, 6, 7 };
     Index i1 = 3; // number 3 from beginning
     Index i2 = ^2; // number 2 from end
     Console.WriteLine($"{numbers[i1]}, {numbers[i2]}"); // "4, 6"

這個例子簡單的演示了一下Index的用法,Index自己仍是相似於以前的int索引的,它也能夠和int類型轉換。但Index在int索引的方式擴展了一下,支持從後往前訪問,也就是咱們說的倒數位。

     Index i2 = ^2; // number 2 from end

Range

基於Index組成起點和終點,能夠組成了一個範圍Range,根據Range能夠對數組進行切片。

     Range range = Range.Create(i1, i2);
     int[] slice = numbers[range];        //"4, 5"

".."運算符

爲了快速表示一個Range,C#還映入了一個新的運算符".."如上面的代碼就能夠簡寫爲:

     int[] slice = numbers[i1..i2];        //"4, 5"

".."語法不復雜,經過".."鏈接的開頭和結尾的索引,用來表示一個範圍。爲了使用方便,".."運算符的開頭和結尾是能夠省略的,經常使用的大體就有這幾種形式。

     string text = "hello c# 8.0";
     Console.WriteLine(text[..]); //"hello c# 8.0"
     Console.WriteLine(text[^3..]);      //"8.0"
     Console.WriteLine(text[..5]);       //"hello"
     Console.WriteLine(text[6..]);       //"c# 8.0"

經過".."運算符,咱們描述切片時能夠清晰不少,例如以下這個常見的求字符串子串的例子:

     var sub = text.Substring(text.Length - 6, 6);
     var sub2 = text[^6..];

.net 3.0的不少類都內置了對Range的切片操做,常見的有:

  1. 字符串用來子串
  2. Array用來劃獲取子數組
  3. span<T>用來切片

 

Asynchronous streams

異步流能一種拉的方式進行異步迭代,配合async編程能夠以異步的方式把socket流像本地文件同樣解析,相信這是不少用c#寫socket程序的程序員所喜歡的一個特性。

一個簡單的示例以下:

     static async IAsyncEnumerable<string> GetNamesAsync()
     {
        await Task.Delay(1000);
        yield return "hello";
        await Task.Delay(1000);
        yield return "world";
     }
    

     await foreach (var name in GetNamesAsync())
     {
        Console.WriteLine(name);
     }

我在Visual Studio 2019 preview中試用這個功能的時候,發現沒法編譯經過。MS解釋說這個是VS和.net core代碼沒有徹底匹配上所致,咱們能夠手動添加相關代碼以完成這一編譯過程。 

namespace System.Threading.Tasks
{
    using System.Runtime.CompilerServices;
    using global::System.Threading.Tasks.Sources;

    internal struct ManualResetValueTaskSourceLogic<TResult>
    {
        private ManualResetValueTaskSourceCore<TResult> _core;
        public ManualResetValueTaskSourceLogic(IStrongBox<ManualResetValueTaskSourceLogic<TResult>> parent) : this() { }
        public short Version => _core.Version;
        public TResult GetResult(short token) => _core.GetResult(token);
        public ValueTaskSourceStatus GetStatus(short token) => _core.GetStatus(token);
        public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _core.OnCompleted(continuation, state, token, flags);
        public void Reset() => _core.Reset();
        public void SetResult(TResult result) => _core.SetResult(result);
        public void SetException(Exception error) => _core.SetException(error);
    }
}

namespace System.Runtime.CompilerServices
{
    internal interface IStrongBox<T> { ref T Value { get; } }
}
View Code

 

其餘語法

自己C# 8.0是還有幾個其它語法的,如接口默認方法,高級模式匹配等。這些語法在目前的VS 2019 preview中還沒法體驗。估計後續會慢慢放開的,到時候我再寫相關文章介紹它們。

相關文章:

https://blogs.msdn.microsoft.com/dotnet/2018/12/05/take-c-8-0-for-a-spin/

相關文章
相關標籤/搜索