C# 9.0 功能預覽 (1) initial only property

C# 9.0 已經進入準備正式公開的階段,讓我們來預覽一下有哪些新鮮玩意兒。

環境
Visual Studio 2019 - 16.8.0 Preview 3.1
.NET 5.0.0-rc.1.20451.14
基本形式

第一個要介紹的是 Init only setter,它其實就是一個 property setter,但是限制外部僅能在物件初始化設定式中設定此屬性值;這裡使用 init 來取代 set 表明它的作用。先來一個簡單的範例:

 class Person
 {
     public string Name { get; init; }
     public int Age { get; init; }
 }

在 Person 類別裡面,表明了 Name 和 Age 這兩個屬性的設定行為,想當然耳使用物件初始化設定式是沒有問題的。但當你想使用指派運算子指派新的值給這些屬性的時候,就會發生錯誤,以下方的程式碼為例, p1.Name = "Tom"; 這一行就會導致編譯例外。

 var p1 = new Person() { Name = "Bill", Age = 12 };
 p1.Name = "Tom";

那可否在建構式設定這些屬性呢?答案是可以的,以下程式碼為合法形式:

 class Person
 {
     public string Name { get; init; }
     public int Age { get; init; }

     public Person(string name, int age)
     {
         Name = name;
         Age = age;
     }
     public Person()
     {        }      
 }

至於結構型別能否使用 init only setter?答案也是可以,例如:

 struct Circle
 {
     public double Radius { get; init; }
 }
這帶來甚麼改變

去年 twMVC#36  我聊了一個題目『C#的美麗與哀愁』,當時提到了 C# 的未來發展會更傾向於非同步和函數式,而這兩個議題中有個很重要的觀念是「Immutable object (不可變物件)」,過去實現不可變物件有個麻煩就是必須完全透過建構式來進行,對於 setter 的部分要嘛就是移除,或是留個小洞變成 private setter,例如以下程式碼:

class Rectangle
 {
     public double Width { get; }

     public double Height { get; }

     public Rectangle (double width, double height)
     {
         Width = width;
         Height = height;
     }
 }

這也可以運作的不錯,但是在屬性多的時候,光寫這個建構式大概就煩死人了;init only setter 提供了一個撰寫不可變物件更為簡潔方案,不需要再煩惱建構式的問題。而且這個新功能會和另一個新個功能 record  有關係,我們下次再聊。

參考資料:Microsoft Docs C# 9.0 中的新增功能