[翻譯] 預覽 C# 10 的新東西
原文: [Introducing C# 10]
作者: Ken Bonny
本周早些時候(譯註:原文發表於5月1日),我關注了 Mads Torgersen 在 DotNet SouthWest 大會上的演講,他是微軟的 C# 語言的首席設計師。他概述了 C# 10 即將包含的很酷的一些新東西。讓我們來快速瀏覽一下。
小小的免責聲明,這些變化中的大部分已經基本完成。但是由於它仍在積極的開發中,我不能保證 C# 10 發布時所有東西都會完全如實。
struct record
他談到的第一件事是,目前 record
的實現是使用一個 class
作為基礎對象的。現在還會有一個 record struct
的變體可用,所以基礎類型可以是一個值類型。區別在於,普通的 record
在函數之間傳遞的是引用,而 record struct
是其值的拷貝。 record struct
也會支援 with
運算符。
同時,還允許向 record
添加運算符,兩種 record
類型都可以。
record Person(string Name, string Email)
{
public static Person operator +(Person first, Person second)
{
// logic goes here
}
}
required
C# 團隊關注的目標之一是使對象的初始化變得更容易。這就是為什麼可以對 class、struct、record 或 struct record 的屬性添加 required 標記 。它使得這些屬性必須填寫。這可以通過構造函數來完成,也可以通過對象初始化來完成。下面的兩個類的定義是等價的。如果你添加了 required 關鍵字,那麼就無法在不設置 Name 屬性的情況下將Person 實例化。編譯器會拋出錯誤,無法編譯。
class Person
{
public required string Name { get; set; }
public DateTime DateOfBirth { get; set; }
}
class Person
{
public Person(string name) => Name = name;
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
}
field
為了進一步的改善屬性,將允許完全擺脫 backing field 。新的關鍵字 field 將提供對上述欄位的訪問。對setter 和 init only 屬性都可以使用。
class Person
{
public string Name { get; init => field = value.Trim(); }
public DateTime DateOfBirth { get; set => field = value.Date; }
}
with
在下一個版本中還會有一些有趣的小改進。其實中一個是匿名類型也將支援 with
運算符。
var foo = new
{
Name = "Foo",
Email = "[email protected]"
};
var bar = foo with {Name = "Bar"};
namespace
現在可以創建一個帶有命名空間導入的文件,然後在任何地方都可以使用這個導入。例如,如果有一個很常用的命名空間,幾乎在每個文件中都使用例如 Microsoft.Extensions.Logging.ILogger
,那麼就可以在任何.cs文件(我建議在 Program.cs 或專門的 Imports.cs )中添加一行 global using Microsoft.Extensions.Logging.ILogger
,之後這個命名空間將可以在整個項目中使用。注意,這不適用於整個解決方案! 沒有人能夠預測哪些地方需要導入,所以它們被分組到每個項目中。
// 譯註:原文並沒有提供程式碼示例,為了更好方便大家理解私自添加了一個演示
// Program.cs 文件
global using System;
// Sample.cs 文件
// 可以不用再using System;
Console.WriteLine("foo");
隨後,還將對命名空間也會有一個優化。現在命名空間需要大括弧 {} 來包起來程式碼,這就意味著所有程式碼至少要縮進一次。為了節省 tab(或四個空格)和螢幕空間,在文件的任何地方添加一個命名空間,將使所有程式碼都屬於該命名空間。有研究表明絕大多數情況下,一個文件中所有的程式碼都屬於同一個命名空間。使用這個方案後,文件大小隨之減少,這對一個解決方案來說可能並不明顯(即使它包含成千上萬的文件),但在GitHub/GitLab/BitBucket/… 的規模上,我認為這將為他們節省一些空間。如果有人仍想在一個文件中包含多個命名空間,使用大括弧的選項仍然可用。
// 傳統的方式 LegacyNamespace.cs
namespace LegacyNamespace
{
class Foo
{
// legacy code goes here
}
}
// 簡化的方式 SimplifiedNamespace.cs
namespace SimplifiedNamespace;
class Bar
{
// awesome code goes here
}
lambda
對 lambda 語句也會有一些很酷的更新。編譯器將對推斷 lambda 簽名提供更好的支援,而且還可以添加特性。話可以顯式指定返回類型,以幫助編譯器理解 lambda。
var f = Console.WriteLine;
var f = x => x; // 推斷返回類型
var f = (string x) => x; // 推斷簽名
var f = [NotNull] x => x; // 添加特性
var f = [NotNull] (int x) => x;
var f = [return: NotNull] static x => x; // 添加特性
var f = T () => default; // 顯式返回類型
var f = ref int (ref int x) => ref x; // 使用 ref
var f = int (x) => x; // 顯式指定隱式輸入的返回類型
var f = static void (_) => Console.Write("Help");
感謝 Schooley 提出了一個不那麼容易混淆的特性例子
interface
最後,將有可能在介面上指定靜態方法和屬性。我知道這將是一個有爭議的話題,就像給介面添加默認實現一樣。我不喜歡它。然而,這可能非常有趣。想像一下,你可以指定一個介面的默認值或指定創建方法。
interface IFoo
{
static IFoo Empty { get; }
static operator +(IFoo first, IFoo second);
}
class Foo : IFoo
{
public static IFoo Empty => new Foo();
public static operator +(IFoo first, IFoo second) => /* do calculation here */;
}
就個人而言,我喜歡這些變化。我最喜歡的是對命名空間的改變和對介面的改進。總之,未來是光明的 C# 的。嗯嗯… (譯註:這裡作者玩了一個梗,原文 the future is seeing sharp,see sharp發音類似 C# )
謝謝各位,大家再見。