C#8.0中新特性之一:結構readonly成員及其相關特性


      在C#8.0中,結構(struct)引入了一項新特性,就是使其成員支持readonly(只讀),這個特性用來限制被其修飾的成員不會改變結構的內部狀態。這項特性,與C#7.2版本添加的readonly struct和ref readonly方法返回、及C#原本之前的只讀字段聲明修飾作用一起,共同組成了目前readonly的四種修飾作用。

一、readonly只讀成員的主要作用

      如前所述,就是被修飾的成員不會改變或者修改結構的內部狀態。

二、readonly只讀成員規則與限制

  1. 只對結構(struct)的成員有效,不能用於類,指示該成員不會修改結構的內部狀態。如果該成員直接修改狀態或者訪問未使用readonly修飾的成員,則結果會報錯。

  2. 不能用於靜態成員和構造函數。

  3. readonly修飾的自動屬性不能有set訪問器。

  4.  readonly添加到屬性或者索引的單個get訪問器中。但同時不能在屬性上有readonly修飾符

  5. readonly函數訪問未標記為readonly的成員時,會發出創建防御性副本的警告。

三、Readonly只讀成員的示例代碼:

//(C# 8.0)結構readonly成員規則及示例:
//1. 只對結構(struct)的成員有效,不能用於類,指示該成員不會修改結構的內部狀態。如果該成員直接修改狀態或者訪問未使用readonly修飾的成員,則結果會報錯。
//2. 不能用於靜態成員和構造函數。
//3. readonly修飾的自動屬性不能有set訪問器。
//4. readonly添加到屬性或者索引的單個get訪問器中。但同時不能在屬性上有readonly修飾符
//5. readonly函數訪問未標記為readonly的成員時,會發出創建防御性副本的警告。
public struct MutablePerson
{
    //結構中靜態字段即可聲明也可初始化
    private static readonly MutablePerson _origin = new MutablePerson();

    //此屬性由ref readonly返回的引用,調用方無法修改來源
    public static ref readonly MutablePerson Origin => ref _origin;

    //ref readonly 只能用於方法或者屬性,不能用於字段。
    //public static ref readonly MutablePerson NewOne; 

    // 結構中字段只能聲明,不能初始化,靜態字段除外
    public static int Population = 100;
    private float _maxAge;
    public string Name;

    //結構中自動屬性只能在此聲明,不能初始化。
    //此自動屬性不能在屬性外添加readonly,因為其中含有set訪問器
    public int Age { get; set; }
    //public readonly int Age { get; set; }

    public float Height {
        //readonly可以添加到屬性或者索引的單個get訪問器中。但同時不能再給屬性上有readonly修飾符
        readonly get; 
        set; }

    //readonly修飾的自動屬性不能有set訪問器。與下面注釋的代碼等效
    readonly public string Nationality { get;}
    //public string Nationality { readonly get; }                                           
    //string _nationality;
    //public string Nationality { readonly get { return _nationality; } set { } }

    readonly public float MaxAge{
        get { return _maxAge; }
        set { } // 沒有用,但是合法
    }


    ////結構中不能包含顯式的無參構造函數,編譯器會自動創建
    //public MutablePerson()
    //{
    //    Name = null;
    //    Age = 0;
    //    Height = 0;
    //}

    //每個構造函數中必須對所有未初始化的字段和自動屬性進行初始化
    public MutablePerson(string name):this(name,0)
    {
        Height = 0.5f; 
        Nationality = "CHINA";
        _maxAge = 100;
    }

    //每個構造函數中必須對所有未初始化的字段和自動屬性進行初始化
    public MutablePerson(string name, int age):this(name,age,0.5f) => 
        (Nationality,_maxAge) = ("CHINA",100);

    //每個構造函數中必須對所有未初始化的字段和自動屬性進行初始化
    public MutablePerson(string name, int age, float height) 
        => (Name, Age, Height, Nationality, _maxAge) = (name, age, height, "CHINA", 100);

    public MutablePerson(MutablePerson other)
    {
        this = other;
    }

    public MutablePerson Replace(MutablePerson other)
    {
        this = other;
        return other;
    }

    //此成員不能用readonly修飾,因為里面代碼會改變成員狀態。
    public void Increase(int ageOffset, float heightOffset) 
    {
        Age += ageOffset;
        Height += heightOffset;
    }

    // readonly 成員中沒有對狀態字段和屬性的任何修改
    public readonly string SayHello => $"Hello, my name is {Name}, I am {Age} and my height is {Height}";

    //readonly函數訪問未標記為readonly的SayHello方法時,會發出創建防御性副本的警告。
    public readonly override string ToString() => $"(Name:{Name}, Age:{Age}, Height:{Height}),{SayHello}";
}

四、其他readonly struct等非8.0相關特性說明

C#7.2 readonly struct 指示結構是不可變的。有如下限制:

  1. 該結構中每個字段和屬性都是readonly

  2. 需要公共構造函數初始化成員

  3. this也是readonly,只能在構造函數中進行初始化賦值

  4. 不能定義像字段樣子的事件

ref readonly用來指示返回的引用,調用方無法修改來源。而readonly修飾的字段,指示該字段在被初始化后,不能再被修改。

具體示例代碼如下:

 

//(C#7.2) readonly struct 指示結構是不可變的。有如下限制:
//1.該結構中每個字段和屬性都是readonly
//2.需要公共構造函數初始化成員
//3.this也是readonly,只能在構造函數中進行初始化賦值
//4.不能定義像字段樣子的事件
public readonly struct ReadonlyPerson
{
    //結構中靜態字段即可聲明也可初始化
    private static readonly ReadonlyPerson _origin = new ReadonlyPerson();

    //由ref readonly返回的引用,調用方無法修改來源。注意此是個屬性
    public static ref readonly ReadonlyPerson Origin => ref _origin;

    //readonly struct對靜態字段沒有效用,不必指定readonly
    public static int Population = 100;

    // 必須給readonly struct中的字段指定readonly。結構中字段只能在此聲明,不能初始化
    public readonly string Name;

    //不能有set訪問器,且只讀自動屬性指示編譯器為這些屬性創建readonly的支持字段。結構中自動屬性只能在此聲明,不能初始化
    public int Age { get; }

    //不能有set訪問器,且只讀自動屬性指示編譯器為這些屬性創建readonly的支持字段。結構中自動屬性只能在此聲明,不能初始化
    public float Height { get; } 

    ////結構中不能包含顯式的無參構造函數,編譯器會自動創建
    //public ReadonlyPerson()
    //{
    //    Name = null;
    //    Age = 0;
    //    Height = 0;
    //}

    public ReadonlyPerson(string name):this(name,0)
    {
        //必須在此初始化,沒有參數必須初始化為默認值,不能在結構聲明中初始化
        Height = 0.5f; 
    }

    //每個構造函數中必須對所有未初始化的字段和自動屬性進行初始化
    public ReadonlyPerson(string name, int age) : this(name, age, 0.5f) 
    { }

    //每個構造函數中必須對所有未初始化的字段和自動屬性進行初始化
    public ReadonlyPerson(string name, int age, float height) 
        => (Name, Age, Height) = (name, age, height);

    public ReadonlyPerson(ReadonlyPerson other)
    {
        this = other;//可以用另一個對象來初始化。
    }

    public MutablePerson Replace(MutablePerson other)
    {
        //this = other; //this是readonly,不能被修改。
        //this.Age = other.Age;//this是readonly,他的成員也是不能被修改。
        return other;
    }

    public void Increase(int ageOffset, float heightOffset)
    {
        //Age += ageOffset; //Age在readonly struct中是只讀的,因此在這里不能被賦值。
        //Height += heightOffset; //Height在 readonly struct中是只讀的,因此在這里不能被賦值。
    }

    // 該成員中沒有對狀態字段和屬性的任何修改
    public string SayHello => $"Hello, my name is {Name}, I am {Age} and my height is {Height}";

    //該函數不能給本結構中的任何字段和屬性做出修改
    public override string ToString() => $"(Name:{Name}, Age:{Age}, Height:{Height}),{SayHello}";

}

 

五、結束語

至此,有關struct相關的readonly的四種修飾及其用法的介紹就到這里,因水平有限,如有錯誤或不妥指出,請指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM