去年公司的 NAS 商城和行動網頁服務的專案翻新至 .NET Core 2.0、2.1,翻新期間 Microsofr .NET Core 3.0 和 C#8 也隨之正式發佈,這才沒過多久,緊接著 C# 9.0 的規格已經進入規劃設計的階段了!不免讓人感嘆新的技術和版本的迭代速度之快。
雖然許多細項還沒定案,我們可以在 Github dotnet csharlang 中的 Milestone 看到許多新規格及功能的提案,今天我們來介紹其中幾項 Design Review 清單中的候選功能,或許還會持續變化,但偶爾關注這些功能的策畫演變也是很有趣的。
1. 簡化參數的 Null 驗證(Simplified Parameter NULL Validation Code)
原本傳入的參數要做 null 驗證,不像 JavaScript 可用兩個驚嘆號去做 Logic Not 反轉判定,必須再傳入後 if-else 加以判斷,C# 9 提案了在變數後方加上一個驚嘆號,可直接判定目標變數是否為空值;此 feature 並不是一個型別,而是只能在 runtime value 上進行檢驗的便利語法糖。範例如下:
1. // Before 2. void Insert(string s) { 3. if (s is null) 4. throw new ArgumentNullException(nameof(s)); 5. ... 6. } 7. 8. // After 9. void Insert(string s!) { 10. ... 11. }
2. 可將 Switch 的表達式視為陳述式(Switch expression as a statement expression)
原本在 C# 7 中使用 Swtich 需如以下程式碼撰寫,也是大多數人所熟悉的 Switch 寫法:
1. public static RGBColor FromRainbowClassic GetArea(Color colorBand) 2. { 3. switch (shape) 4. { 5. case Color.Red: 6. return new RGBColor(0xFF, 0x00, 0x00); 7. case Color.Orange: 8. return new RGBColor(0xFF, 0x7F, 0x00); 9. case Color.Yellow: 10. return new RGBColor(0xFF, 0xFF, 0x00); 11. default: 12. throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)); 13. } 14. }
而 C# 8 中允許了 Switch 使用運算式精簡語法,能使程式碼更加精煉:
1. public static RGBColor FromRainbow(Rainbow colorBand) => 2. colorBand switch 3. { 4. Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00), 5. Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00), 6. Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00), 7. _ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)), 8. };
而這次新版本的提案是開放可在 Switch 的表達式中使用陳述式,C# 9 的 Milestone 中這項提案,原本被放在 C# 8.X 的目標中,後來被轉移至 9.0。目前這項功能仍處於還沒定案的討論階段:
1. void M(bool c, ref int x, ref string s) 2. { 3. c switch { true => x = 1, false => s = null }; 4. }
3.Primary Constructors
在 C# 9 中提出了類似 TypeScript 語言中的簡化 Constructors,原本的 Constructor 需如以下撰寫:
1. public class Car{ 2. private readonly int _wheels; 3. public Car(int wheels){ 4. _wheels = wheels; 5. } 6. ... 7. }
在提案中,新的寫法可使用更精簡的方式宣告:
1. public class Car(int _wheels){ 2. ... 3. }
然而此種宣告方式可能會帶來語義與原宣告方式不甚一致的狀況,這方面的疑慮或許可以經由其他擴展方式消除,但勢必連帶出其他需求,且此種精簡宣告方式僅限於當只有單一 Constructor 存在時才能使用。在提案文件中詳細列出了可能的備案,有興趣進一步了解的人可參考 primary-constructors.md。
4. Record Classes
Record Classes 和 Primary Constructor 概念類似,目標為大量減少在創建新類別時出現的模板代碼,目前看提案內容,和 Primary Constructor 兩者應是只能擇一存在。
1. public class Person 2. { 3. public string Name { get; } 4. public DateTime DateOfBirth { get; } 5. 6. public Person(string Name, DateTime DateOfBirth) 7. { 8. this.Name = Name; 9. this.DateOfBirth = DateOfBirth; 10. } 11. } 12. //簡化之後 13. public class Person(string Name, DateTime DateOfBirth);
5. 經由 Enum 類別做差別聯集(Discriminated Unions via Enum Classes )
簡單來說,這項提議的目的與上述幾項類似,利用 enum 特性簡化 Class 的宣告方式,例如:
1. enum class Shape 2. { 3. Rectangle(float Width, float Length), 4. Circle(float Radius) 5. }
此種 enum class 的宣告方式等同於以下程式碼:
1. partial abstract class Shape 2. { 3. public data class Rectangle(float Width, float Length) : Shape, 4. public data class Circle(float Radius) : Shape 5. }
Enum 類別為以上五項提議中爭議最大的一項,之後再產生變數的可能性不低,而此篇文章截選了討論度較高的五項提案,Github milestone有更多的proposal內容,大家可以再持續關注 C#9 的規格進展。
Reference
