C# 9.0 新特性預覽 - init-only 屬性
前言
隨著 .NET 5 發布日期的日益臨近,其對應的 C# 新版本已確定為 C# 9.0,其中新增加的特性(或語法糖)也已基本鎖定,本系列文章將向大家展示它們,
目錄
[C# 9.0 新特性預覽 - 型別推導的 new]
[C# 9.0 新特性預覽 - 空引數校驗]
[C# 9.0 新特性預覽 - 頂級陳述句]
[C# 9.0 新特性預覽 - init-only 屬性]
[C# 9.0 新特性預覽 - Record 型別]
[C# 9.0 新特性預覽 - 模式匹配的改善]
[C# 9.0 新特性預覽 - 源代碼生成器]
[C# 9.0 新特性預覽 - 其他小的變化]
只初始化 setter (Init Only Setters)
這個特性允許創建只初始化(init only)的屬性和索引器,使得 C# 中的不可變模型更加靈活,
背景
在此之前,我們創建物體類/POCO類/DTO類等等模型類的時候,都期望屬性只讀不允許從外部修改,會將屬性的 setter 設為私有或者干脆不設定 setter,例如:
public class Person
{
public string Name { get; private set; }
// OR
//public string Name { get; }
}
再添加一個擁有全部屬性作為簽名的構造方法:
...
public Person(string name)
{
this.Name = name;
}
...
這樣做雖然可以達到目的,但是帶來了兩個問題
1.假如屬性增多,會帶來作業量的成倍增加,以及不易維護
2.無法使用物件初始化器(object initializers)
var person = new Person
{
Name = "Rwing" // Compile Error
};
在這個情況下,init 關鍵字應運而生了,
語法
語法很簡單,只需要將屬性中的 set 關鍵字替換為 init 即可:
public string Name { get; init; }
以上代碼會被大致翻譯為:
private readonly string _name;
public string Name
{
get { return _name; }
set { _name = value;}
}
可以看到,與 set 的區別是,init 會為背后的欄位添加 readonly 關鍵字,
這樣我們就可以去掉一堆屬性的構造方法轉而使用物件初始化器了,并且達到了不可變的目的,
var person = new Person
{
Name = "Rwing"
};
// 初始化后無法再次修改
person.Name = "Foo"; // Error: Name is not settable
這一語法,有很多場景需要配合同樣在 C# 9.0 中新增的 record 型別使用,
哪些情況下可以被設定
- 通過物件初始化器
- 通過 with 運算式
- 在自身或者派生類的構造方法中
- 在標記為 init 的屬性中
- 在特性(attribute)類的命名引數屬性中
以上場景不難理解,但是值得一提的是,只有 get 的屬性是不可以派生類的構造方法中賦值的,但是 init 可以:
class Base
{
public bool Foo { get; init; }
public bool Bar { get; }
}
class Derived : Base
{
Derived()
{
Foo = true;
Bar = true; // ERROR
}
}
此外有一種例外, 在以上場景中的 lambda 或本地函式中,也不允許被設定,例如:
原因也很簡單,lambda 或本地函式在編譯后已經不在建構式中了,
public class Class
{
public string Property { get; init; }
Class()
{
System.Action a = () =>
{
Property = null; // ERROR
};
local();
void local()
{
Property = null; // ERROR
}
}
}
參考
[Proposal: Init Only Setters]
[InitOnlyMemberTests.cs]
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/194129.html
標籤:C#
上一篇:開源!一款功能強大的高性能二進制序列化器Bssom.Net
下一篇:五種檔案夾選擇框的實作方法整理 FolderBrowserDialog OpenFileDialog FolderBrowserDialog 支持輸入路徑的檔案夾選擇框
