C#——关键字:readonly
C#——关键字:readonly
readonly 关键字是一个可在四个上下文中使用的修饰符:
-
在字段声明中,readonly 指示只能在声明期间或在同一个类的构造函数中向字段赋值。 可以在字段声明和构造函数中多次分配和重新分配只读字段。
构造函数退出后,不能分配 readonly 字段。 此规则对于值类型和引用类型具有不同的含义:
1.由于值类型直接包含数据,因此属于 readonly 值类型的字段不可变。
2.由于引用类型包含对其数据的引用,因此属于 readonly 引用类型的字段必须始终引用同一对象。 该对象是可变的。 readonly 修饰符可防止字段替换为引用类型的其他实例。 但是,修饰符不会阻止通过只读字段修改字段的实例数据。
警告
包含属于可变引用类型的外部可见只读字段的外部可见类型可能存在安全漏洞,可能会触发警告 CA2104:“不要声明只读可变引用类型。” -
在 readonly struct 类型定义中,readonly 指示结构类型是不可变的。 有关详细信息,请参阅结构类型一文中的 readonly 结构一节。
-
在结构类型内的实例成员声明中,readonly 指示实例成员不修改结构的状态。 有关详细信息,请参阅结构类型一文中的 readonly 实例成员部分。
-
在 ref readonly 方法返回中,readonly 修饰符指示该方法返回一个引用,且不允许向该引用写入内容。
在 C# 7.2 中添加了 readonly struct 和 ref readonly 上下文。 在 C# 8.0 中添加了 readonly 结构成员
Readonly 字段示例
在此示例中,即使在类构造函数中给字段 year 赋了值,也无法在方法 ChangeYear 中更改其值:
class Age
{
readonly int year;
Age(int year)
{
this.year = year;
}
void ChangeYear()
{
//year = 1967; // Compile error if uncommented.
}
}
只能在下列上下文中对 readonly 字段进行赋值:
- 在声明中初始化变量时,例如:
public readonly int y = 5;
- 在包含实例字段声明的类的实例构造函数中。
- 在包含静态字段声明的类的静态构造函数中。
只有在这些构造函数上下文中,将 readonly 字段作为 out 或 ref 参数传递才有效。
备注:
readonly 关键字不同于 const 关键字。 const 字段只能在该字段的声明中初始化。 可以在字段声明和任何构造函数中多次分配 readonly 字段。 因此,根据所使用的构造函数,readonly 字段可能具有不同的值。 另外,虽然 const 字段是编译时常量,但 readonly 字段可用于运行时常量,如下面的示例所示:
public static readonly uint timeStamp = (uint)DateTime.Now.Ticks;
public class SamplePoint
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;
public SamplePoint()
{
// Initialize a readonly instance field
z = 24;
}
public SamplePoint(int p1, int p2, int p3)
{
x = p1;
y = p2;
z = p3;
}
public static void Main()
{
SamplePoint p1 = new SamplePoint(11, 21, 32); // OK
Console.WriteLine($"p1: x={p1.x}, y={p1.y}, z={p1.z}");
SamplePoint p2 = new SamplePoint();
p2.x = 55; // OK
Console.WriteLine($"p2: x={p2.x}, y={p2.y}, z={p2.z}");
}
/*
Output:
p1: x=11, y=21, z=32
p2: x=55, y=25, z=24
*/
}
在前面的示例中,如果使用类似以下示例的语句:
p2.y = 66; // Error
你将收到编译器错误消息:
无法对只读的字段赋值(构造函数或变量初始值指定项中除外)
Ref readonly 返回示例
ref return 上的 readonly 修饰符指示返回的引用无法修改。 下面的示例返回了一个对来源的引用。 它使用 readonly 修饰符来指示调用方无法修改来源:
private static readonly SamplePoint origin = new SamplePoint(0, 0, 0);
public static ref readonly SamplePoint Origin => ref origin;
所返回的类型不需要为 readonly struct。 ref 能返回的任何类型都能由 ref readonly 返回。