朝C#9前進

朝C#9前進

去年公司的 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

https://github.com/dotnet/csharplang/milestone/15

https://github.com/dotnet/csharplang/blob/master/proposals/primary-constructors.md


發表迴響

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料