开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第26天,点击查看活动详情
readonly
修饰的属性或字段,只能在构造函数或创建对象时赋值。
readonly 的适用范围
readonly 修饰符可以用在以下4个上下文中:
- 字段声明中,readonly 表示只能在声明时或同一个类的构造函数中赋值。
由于值类型直接包含它们的数据,readonly
值类型的字段是不可变的。
但是,引用类型包含对数据的引用,readonly
引用类型必须始终引用相同的对象,该对象不是不可变的,readonly
修饰符阻止字段被不同的引用类型实例所替换,但不能阻止字段的实例数据被修改。
-
在
readonly struct
类型定义中,readonly
指示该结构类型是不可变的。 -
结构类型内的实例成员声明中,
readonly
指示该实例成员不会修改结构体的状态。如果该成员直接修改结构体的状态或者访问未使用readonly修饰的成员,则会报错。 -
在 ref readonly method return 中,只读修饰符指示该方法返回引用类型,并且不允许修改该引用。
在 C# 7.2 中添加了 readonly struct 和 ref readonly 上下文,在 C# 8.0 中添加了 readonly 结构成员。
readonly 修饰引用类型,可防止该引用类型变量被重新赋值,但是不能防止引用类型实例内部的数据被修改。即防止引用的地址被修改(引用本身(相当于指针)不可改变),但地址里面的数据可以修改。
readonly 字段
在下面的示例中,字段_year
不允许在ChangeYear
方法内被修改
class Age
{
private readonly int _year;
Age(int year)
{
_year = year;
}
void ChangeYear()
{
//_year = 1967; // Compile error if uncommented.
}
}
只能在以下情况下为 readonly
字段赋值:
- 变量声明的初始化时。
- 包含实例字段声明的实例构造函数中
- 包含静态字段声明的静态构造函数中
readonly
修饰的自动属性不能有set访问器,可以有init初始化访问器。
readonly函数访问未标记为readonly的成员时,会发出创建防御性副本的警告。
readonly 与 const 的区别
const 字段只能在声明字段时被初始化;
readonly 字段可以在字段声明和构造器中赋值多次。因此,取决于构造器的使用,readonly 字段可以有不同的值。
因此,const 字段可以看做是编译时常量或静态常量,readonly 字段可以用做运行时常量或动态常量。
对于引用类型,应该使用 readonly,这是因为引用类型是动态分配内存,不可能在编译阶段就确定它的地址,这也是和值类型(包括string)完全不一样的。
能使用 const 修饰符的需要是常量,即 基元类型,枚举类型或者字符串类型,而不能是class、struct等类型。
const 关键字声明的字段本身就是 static 静态的,只能通过 类名 对 const 常量进行访问。
class Person
{
public const int age = 10;
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Person.age);
}
}
const
与 static readonly
基本相似,但是在初始化方面,static readonly
还可以通过静态构造函数进行赋值。const
在程序编译期间获取字段的值,而 static readonly
是在程序运行时获取字段的值。
public class Person
{
public static readonly int age = 10;
static Person()
{
age = 12;
}
}
class Program
{
static void Main(string[] args)
{
Person Person = new Person();
Console.WriteLine(Person.age);
}
}
静态常量(Const)是指编译器在编译时候会对常量进行解析,并将常量的值替换成初始化的那个值。
动态常量(Readonly)的值则是在运行的那一刻才获得的,编译器编译期间将其标示为只读常量,而不用常量的值代替,这样动态常量不必在声明的时候就初始化,而可以延迟到构造函数中初始化。
Const的变量是嵌入在IL代码中,编译时就加载好,不依赖外部dll(这也是为什么不能在构造方法中赋值),只能在声明初始化时赋值。Const在程序集更新时容易产生版本不一致的情况。
Readonly的变量是在运行时加载,需请求加载dll,每次都获取最新的值。
Readonly修饰引用类型,引用本身不可以改变,但是引用所指向的实例的值是可以改变的。
在声明初始化、构造方法中,可以对 Readonly 变量多次赋值。
ref readonly return
ref return
的 readonly 修饰符指示返回的引用不能被修改。
下面的示例返回一个对origin的引用,使用readonly修饰符指示调用者不能修改origin:
private static readonly SamplePoint s_origin = new SamplePoint(0, 0, 0);
public static ref readonly SamplePoint Origin => ref s_origin;