隨著 .NET 5 發佈日期的日益臨近,其對應的 C# 新版本已確定為 C# 9.0,其中新增加的特性(或語法糖)也已基本鎖定,本系列文章將向大家展示它們。 ...
C# 9.0 新特性預覽 - 類型推導的 new
前言
隨著 .NET 5 發佈日期的日益臨近,其對應的 C# 新版本已確定為 C# 9.0,其中新增加的特性(或語法糖)也已基本鎖定,本系列文章將向大家展示它們。
目錄
[C# 9.0 新特性預覽 - 類型推導的 new]
[C# 9.0 新特性預覽 - Lambda 中的棄元]
[C# 9.0 新特性預覽 - 更簡便的空參數檢查]
[C# 9.0 新特性預覽 - Record 類型]
[C# 9.0 新特性預覽 - 模式匹配的改善]
[C# 9.0 新特性預覽 - 其他小的變化]
具有類型推導的 new 表達式 (Target-typed new expressions)
這是一個本應隨著 C# 8.0 發佈的語言特性,但因種種原因在發佈 C# 8.0 的最後關頭,它被移出了最終的發佈版本,下麵我們來認識認識它。
大家都知道,C# 在3.0中新增 var 關鍵字來做隱式類型聲明,把繁重的聲明語法簡化了。
Dictionary<string, List<int>> field = new Dictionary<string, List<int>>()
// 可以簡化為
var field = new Dictionary<string, List<int>>()
var 關鍵字的基本原理不再覆述,簡單說就是編譯器可以根據等號後面的類型推導出 var 的類型,那麼是不是也可以反過來,我們先聲明類型,接下來的 new 關鍵字後面就不用寫類型了呢?於是本文介紹的特性來了:
Dictionary<string, List<int>> field = new Dictionary<string, List<int>>()
// C# 9.0 中可以寫成
Dictionary<string, List<int>> field = new()
從以上代碼可以看出語法很簡單,即省略了繁瑣的可以推導出的類型。
其語法 Spec 如下:
'new' '(' argument_list? ')' object_or_collection_initializer?
搭配初始化器,我們可以進一步簡化帶有初始值的初始化。
Dictionary<string, List<int>> field = new() {
{ "item1", new() { 1, 2, 3 } }
};
進一步展示該語法在各種情況下的使用
在所有可以推導出類型的上下文中,都可以使用,例如:
XmlReader.Create(reader, new() { IgnoreWhitespace = true });
帶有參數的構造方法:
class C {
C(params int[] p) {}
}
C c = new(1, 2, 3);
調用方法時:
class A {}
static void M(A a) {};
M(a: new());
配合對象初始化器:
X x = new() { field = 42 };
泛型的類型推導,需要註意,要有一個顯示類型聲明才能正確推導:
void M<T>(T t1, T t2) {}
M(new X(), new());
類似的,數組的聲明
var arr = new[] {new X(), new()};
不適用此特性的場景
值類型的初始化,可以使用 default 替代
int x = new(); // ERROR
Struct y = new(); // ERROR
使用 as 操作時無法正確推導
Console.Write(new() as X); // ERROR
自然,使用 var 時也無法推導
var x = new(); // ERROR
有歧義的重載
void M(object a, X b) => Console.Write($"{a} {b}");
void M(X a, object b) => Console.Write($"{a} {b}");
M(new(), new()); // ERROR
需要註意的地方
這個新語法 new(),比較容易與匿名類型語法混淆 new{},它們兩個是完全不同的東西,需要註意一下。
參考
[Proposal: Target-typed new expressions]
[Unit test: TargetTypedNewTests.cs]