readonly(C# 参考)

readonly 关键字是一个可在五个上下文中使用的修饰符:

  • 字段声明中,readonly 指示只能在声明期间或在同一个类的构造函数中向字段赋值。 可以在字段声明和构造函数中多次分配和重新分配只读字段。

    构造函数退出后,不能分配 readonly 字段。 此规则对于值类型和引用类型具有不同的含义:

    • 由于值类型直接包含数据,因此属于 readonly 值类型的字段不可变。
    • 由于引用类型包含对其数据的引用,因此属于 readonly 引用类型的字段必须始终引用同一对象。 该对象可能是可变的。 readonly 修饰符可防止将字段值替换为引用类型的其他实例。 但是,修饰符不会阻止通过只读字段修改字段的实例数据。

    警告

    包含属于可变引用类型的外部可见只读字段的外部可见类型可能存在安全漏洞,可能会触发警告 CA2104:“不要声明只读可变引用类型。”

  • readonly struct 类型定义中,readonly 指示结构类型是不可变的。 有关详细信息,请参阅结构类型一文中的 readonly 结构一节。

  • 在结构类型内的实例成员声明中,readonly 指示实例成员不修改结构的状态。 有关详细信息,请参阅结构类型一文中的 readonly 实例成员部分。

  • ref 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 字段进行赋值:

  • 在声明中初始化变量时,例如:

    public readonly int y = 5;
    
  • 在包含实例字段声明的类的实例构造函数中。

  • 在包含静态字段声明的类的静态构造函数中。

只有在这些构造函数上下文中,将 readonly 字段作为 outref 参数传递才有效。

注意

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

收到编译器错误消息:

无法对只读的字段赋值(构造函数或变量初始值指定项中除外)

只读实例成员

还可以使用 readonly 修饰符来声明实例成员不会修改结构的状态。

public readonly double Sum()
{
    return X + Y;
}

注意

对于读/写属性,可以将 readonly 修饰符添加到 get 访问器。 某些 get 访问器可以执行计算并缓存结果,而不是只返回专用字段的值。 将 readonly 修饰符添加到 get 访问器可确保 get 访问器不会通过缓存任何结果来修改对象的内部状态。

可在结构类型一文中的 readonly 实例成员部分查看更多示例。

Ref readonly 返回示例

ref return 上的 readonly 修饰符指示返回的引用无法修改。 下面的示例返回了一个对来源的引用。 它使用 readonly 修饰符来指示调用方无法修改来源:

private static readonly SamplePoint s_origin = new SamplePoint(0, 0, 0);
public static ref readonly SamplePoint Origin => ref s_origin;

所返回的类型不需要为 readonly structref 能返回的任何类型都能由 ref readonly 返回。

只读 Ref readonly return 示例

还可以将 ref readonly returnstruct 类型上的 readonly 实例成员结合使用:

public struct ReadonlyRefReadonlyExample
{
    private int _data;

    public readonly ref readonly int ReadonlyRefReadonly(ref int reference)
    {
        // _data = 1; // Compile error if uncommented.
        return ref reference;
    }
}

该方法本质上返回一个 readonly 引用,以及状态为 readonly(无法修改任何实例字段)的实例成员(在本例中为方法)。

C# 语言规范

有关详细信息,请参阅 C# 语言规范。 该语言规范是 C# 语法和用法的权威资料。

你还可查看语言规范建议:

请参阅