C# 9.0 新特性之目標型別推導 new 表示式

LiamWang發表於2020-06-16

閱讀本文大概需要 2 分鐘。

呼~~,每次過完一個週末,寫作就失去了動力,一兩天才能緩過來。儘管如此,還是要堅持寫好每一篇文章的。寧缺毋濫嘛,寧願發文的頻率低一點,也要保證文章的質量,至少排版不能差,行文要流暢,錯別字不能有。

關於型別推導想必大家都很熟悉,它是在 var 關鍵字引入的時候引入 C# 的。

var i = 10;
var u = new User();

編譯器會通過右邊的字面量自動推導左邊變數的型別,這種推導方式可以歸納為:從上下文右邊推匯出左邊的型別。我們不妨把它稱為源型別推導(Source-typed inferring,參考 Target-typed 自創的術語)。

相應的,有源型別推導就有目標型別推導 (Target-typed inferring),它是指從上下文左邊推匯出右邊的型別。比如陣列的初始化和 Lambda 表示式常常是目標型別推導的表示式。舉個例子:

// 沒有使用型別推導
string[] s = new string[] { "a", "b" };
// 目標型別推導(左推右)
string[] s = new { "a", "b" };
string[] s = new [] { "a", "b" };

// 沒有使用型別推導
Users.FirstOrDefault<User>(u => u.id = 123);
// 目標型別推導(左推右)
Users.FirstOrDefault(u => u.id = 123);

這次在 C# 9 中,增加了使用者定義型別 new 表示式的目標型別推導,即通過上下文左邊自動推導 new 表示式的型別,從而在使用 new 構造時省略型別的指定,請看示例:

// C# 9 之前
Point p = new Point(3, 5);

// C# 9
Point p = new (3, 5);

除此之外,C# 9 也增加了操作符 ???: 的目標型別推導支援。之前這兩個操作符必須要求兩邊的操作物件都是相同的型別,否則會編譯報錯。而在 C# 9 中,只要目標型別是操作物件共同的基類就不再會編譯報錯了,比如:

// Student 和 Customer 擁有共同的父類 Person
Person person = (Person)(student ?? customer); // C# 9 之前
Person person = student ?? customer; // C# 9

// 可空型別,0 和 null 都可以隱式轉換為 int? 型別
int? result = b ? 0 : (int?)null; // C# 9 之前
int? result = b ? 0 : null; // C# 9

其實本文的核心就一句程式碼:

Point p = new (3, 5);

卻一不小心囉嗦了這麼一堆。但講真,學習新的知識不是要死記硬背,而要學會歸類推理,舉一反三,經常思考,最好能形成自己的一種思維習慣,這樣學習才會變成一件水到渠成的事。多看我的文章,希望你能學到的不僅僅是生硬的程式設計知識點,也希望我的行文風格和思維習慣對你有所啟發。

相關文章