结构struct成员支持readonly,用来限制被其修饰的成员不会改变结构的内部状态。加上7.2版本添加的readonly struct和ref readonly方法返回以及之前的字段声明修饰作用,现在readonly一共有四种修饰作用。下面两段代码以及注释进行了说明。
//(v8.0)readonly成员: //1. 只对struct成员有效,指示该成员不会修改结构的内部状态。如果该成员直接修改状态或者访问未使用readonly修饰的成员,则结果会报错。 //2. 不能用于静态成员和构造函数。 public struct MutablePerson { private static readonly MutablePerson _origin = new MutablePerson(); //结构中静态字段即可声明也可初始化 //---------start ref readonly--------------- public static ref readonly MutablePerson Origin => ref _origin;//由ref readonly返回的引用,调用方无法修改来源。注意此是个属性 //public static ref readonly MutablePerson NewOne; //ref readonly 只能用于方法或者属性,不能用于字段。 //---------end ref readonly--------------- public static int Population = 100; private float _maxAge; public string Name; // 结构中字段只能在此声明,不能初始化 public int Age { get; set; }//结构中自动属性只能在此声明,不能初始化。 //public int Age { readonly get; set; } public float Height { readonly get; //readonly可以添加到属性或者索引的单个get或者set访问器中。但同时不能再给属性上有readonly修饰符 set; } readonly public string Nationality { get;} //readonly修饰的自动属性不能有set访问器。与下面注释的代码等效 //public string Nationality { readonly get; } //public string Nationality { readonly get{return _nationality;} set{}} string _nationality; readonly public float MaxAge{ get { return _maxAge; } set { } // 没有用,但是合法 } ////结构中不能包含显式的无参构造函数,编译器会自动创建 //public Point() //{ // 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; } public void Increase(int ageOffset, float heightOffset) //此成员不能用readonly修饰,因为里面代码会改变成员状态。 { 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}"; }
//(v7.2)readonly struct 指示Point是不可变的。有如下限制: //1.该结构中每个字段和属性都是readonly //2.需要公共构造函数初始化成员 //3.this也是readonly,只能再构造函数中进行初始化赋值 //4.不能定义像字段样子的事件 public readonly struct ReadonlyPerson { private static readonly ReadonlyPerson _origin = new ReadonlyPerson(); //结构中静态字段即可声明也可初始化 public static ref readonly ReadonlyPerson Origin => ref _origin; //由ref readonly返回的引用,调用方无法修改来源。注意此是个属性 public static int Population = 100; //readonly struct对静态字段没有效用,不必指定readonly public readonly string Name; // 必须给readonly struct中的字段指定readonly。结构中字段只能在此声明,不能初始化 public int Age { get; }//不能有set访问器,且只读自动属性指示编译器为这些属性创建readonly的支持字段。结构中自动属性只能在此声明,不能初始化 public float Height { get; } //不能有set访问器,且只读自动属性指示编译器为这些属性创建readonly的支持字段。结构中自动属性只能在此声明,不能初始化 ////结构中不能包含显式的无参构造函数,编译器会自动创建 //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}"; }