C#8.0 於 2019年4月 隨 .NET Framework 4.8 與 Visual Studio 2019 一同發佈express
使用VS2019體檢C#8.0新功能:數組
編輯.csproj文件,添加以下代碼異步
<PropertyGroup> <LangVersion>preview</LangVersion> </PropertyGroup>
引用類型將會區分是否可空,能夠從根源上解決 NullReferenceException。async
#nullable enable void M(string? s) { Console.WriteLine(s.Length); // 產生警告:可能爲 null if (s != null) { Console.WriteLine(s.Length); // Ok } } #nullable disable
考慮到大部分 Api 以及函數實現都有了對應的 async版本,而 IEnumerable<T>和 IEnumerator<T>還不能方便的使用 async/await就顯得很麻煩了。
可是,如今引入了異步流,這些問題獲得瞭解決。
咱們經過新的 IAsyncEnumerable<T>和 IAsyncEnumerator<T>來實現這一點。同時,因爲以前 foreach是基於IEnumerable<T>和 IEnumerator<T>實現的,所以引入了新的語法await foreach來擴展 foreach的適用性。函數
async Task<int> GetBigResultAsync() { var result = await GetResultAsync(); if (result > 20) return result; else return -1; } async IAsyncEnumerable<int> GetBigResultsAsync() { await foreach (var result in GetResultsAsync()) { if (result > 20) yield return result; } }
C# 8.0 引入了 Index 類型,可用做數組下標,而且使用 ^ 操做符表示倒數。
不過要注意的是,倒數是從 1 開始的。spa
Index i1 = 3; // 下標爲 3 Index i2 = ^4; // 倒數第 4 個元素 int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"
除此以外,還引入了 「..」 操做符用來表示範圍(注意是左閉右開區間)。code
var slice = a[i1..i2]; // { 3, 4, 5 }
關於這個下標從 0 開始,倒數從 1 開始,範圍左閉右開。blog
典型的模式匹配語句,只不過沒有用「match」關鍵字,而是沿用了了「switch」關鍵字遞歸
object figure = ""; var area = figure switch { Line _ => 0, Rectangle r => r.Width * r.Height, Circle c => c.Radius * 2.0 * Math.PI, _ => throw new UnknownFigureException(figure) };
C# 8.0中的模式匹配相對C# 7.0來講有了進一步的加強,對於以下類:get
class Point { public int X { get; } public int Y { get; } public Point(int x, int y) => (X, Y) = (x, y); public void Deconstruct(out int x, out int y) => (x, y) = (X, Y); }
首先來看C# 7.0中一個經典的模式匹配示例:
static string Display(object o) { switch (o) { case Point p when p.X == 0 && p.Y == 0: return "origin"; case Point p: return $"({p.X}, {p.Y})"; default: return "unknown"; } }
在C# 8.0中,它有更加精簡的寫法。
在C# 8.0中,能夠利用新的switch方式成模式匹配:
static string Display(object o) => o switch { Point p when p.X == 0 && p.Y == 0 => "origin", Point p => $"({p.X}, {p.Y})", _ => "unknown" };
它利用一條switch語句完成了模式匹配,第同樣看上去要簡潔一些。不過,它還有更多更簡單的寫法。
能夠直接經過在屬性上指定值做爲斷定條件,
static string Display(object o) => o switch { Point { X: 0, Y: 0 } => "origin", Point p => $"({p.X}, {p.Y})", _ => "unknown" };
也能夠將屬性值傳遞出來。
static string Display(object o) => o switch { Point { X: 0, Y: 0 } => "origin", Point { X: var x, Y: var y } => $"({x}, {y})", _ => "unknown" };
利用解構函數,能夠寫出更加精簡的表達式。
static string Display(object o) => o switch { Point(0, 0) => "origin", Point(var x, var y) => $"({x}, {y})", _ => "unknown" };
若是沒有類型轉換,則能夠寫得更加簡單了:
static string Display(Point o) => o switch { (0, 0) => "origin", (var x, var y) => $"({x}, {y})" };
若是隻是判斷空和非空,則有最簡單的模式:
{ } => o.ToString(), null => "null"
也支持直接對ValueTuple進行模式匹配,用起來很是靈活。
static State ChangeState(State current, Transition transition, bool hasKey) => (current, transition, hasKey) switch { (Opened, Close, _) => Closed, (Closed, Open, _) => Opened, (Closed, Lock, true) => Locked, (Locked, Unlock, true) => Closed, _ => throw new InvalidOperationException($"Invalid transition") };
如今能夠這麼寫了(patterns 裏能夠包含 patterns)
IEnumerable<string> GetEnrollees() { foreach (var p in People) { if (p is Student { Graduated: false, Name: string name }) yield return name; } }