C# 中的只讀結構體(readonly struct)

技術譯民發表於2020-10-28

翻譯自 John Demetriou 2018年4月8日 的文章 《C# 7.2 – Let’s Talk About Readonly Structs》[1]

在本文中,我們來聊一聊從 C# 7.2 開始出現的一個特性 readonly struct

任一結構體都可以有公共屬性、私有屬性訪問器等等。我們從以下結構體示例來開始討論:

public struct Person
{
    public string Name { get; set; }

    public string Surname { get; set; }

    public int Age { get; set; }

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

    public void Replace(Person other)
    {
        this = other;
    }
}

如您所見,所有屬性都可以公開訪問和修改。更糟糕的是,我們甚至可以訪問 this (通過呼叫 Replace 方法),將其更改為同一結構體型別的另一個例項。
這就是 readonly 關鍵字出現的原因。如果(僅)在結構體的定義中新增它,如下所示:

public readonly struct Person
{
    public string Name { get; set; }

    public string Surname { get; set; }

    public int Age { get; set; }

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

    public void Replace(Person other)
    {
        this = other;
    }
}

編譯器會顯示如下面截圖中的錯誤提示:

readonly struct error

為什麼會這樣?這是因為當我們向結構體定義新增 readonly 關鍵字,其實是把每個屬性都設定為只讀的了,包括 this 的值。

要讓程式碼通過編譯的唯一方法是把所有內容都設定為只讀的,也就是說我們的結構體應該像這樣:

public readonly struct Person
{
    public string Name { get; }

    public string Surname { get; }

    public int Age { get; }

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

因此,新增 readonly 可以消除結構體例項內部或外部發生意外賦值或修改值的可能性。不過,需要注意的一件事是,如果您經常使用無參建構函式並給屬性賦值,像這樣:

Person s = new Person();
//錯誤
s.Age = 15;
s.Name = "asd";
s.Surname = "qwe";

或者像這樣:

//錯誤
Person s = new Person
{
    Age = 15,
    Name = "asd",
    Surname = "qwe"
};

雖然此結構體的預設無參建構函式仍然可以呼叫,但給任何屬性賦值都將引發編譯錯誤,因為屬性是隻讀的。
實際上,對此結構體的無參建構函式的呼叫會將其所有屬性設定為它們的預設值,而且在結構體例項的整個生命週期中,永遠不會被修改。
正確的初始化方法是呼叫引數化建構函式:

Person s = new Person("asd", "qwe", 15);

總之,這將有助於更容易地表明您的意圖,因為您可以從一開始就定義這個結構體是不可變和不可修改的。

譯者總結

使用 readonly 修飾符宣告 struct 的目的就是為了明確地宣告一個不可變的值型別。

readonly 結構體的所有資料成員都必須是隻讀的:

  1. 所有欄位宣告都必須具有 readonly 修飾符
  2. 所有屬性(包括自動實現的屬性)都必須是隻讀的

這就保證了 readonly 結構體的成員不會修改該結構體的狀態。在 C# 8.0 及更高版本中,除建構函式外的其他例項成員都是隱式 readonly 的。


作者 : John Demetriou
譯者 : 技術譯民
出品 : 技術譯站
連結 : 英文原文


  1. https://www.devsanon.com/c/c-7-2-lets-talk-about-readonly-structs/ C# 7.2 – Let’s Talk About Readonly Structs ↩︎

相關文章