readonly (C# 参考)

在五个上下文中将 readonly 关键字用作修饰符:

  • 字段声明中readonly 意味着只能在声明期间或在同一类的构造函数中分配字段。 可以在字段声明和构造函数中多次分配和重新分配只读字段。

    构造函数完成后无法分配 readonly 字段。 此规则以不同的方式影响值类型和引用类型:

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

    警告

    包含外部可见只读字段的外部可见类型,该字段是可变引用类型,可能是一个安全漏洞,并可能会触发警告 CA2104 :“不要声明只读可变引用类型。

  • readonly struct在类型定义中,readonly表示结构类型是不可变的。 有关详细信息,请参阅readonly结构类型文章的结构部分。

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

  • ref readonly在方法返回中,readonly修饰符指示该方法返回引用,不允许写入该引用。

C# 语言参考记录了 C# 语言的最新发布版本。 它还包含即将发布的语言版本公共预览版中功能的初始文档。

本文档标识了在语言的最后三个版本或当前公共预览版中首次引入的任何功能。

小窍门

若要查找 C# 中首次引入功能时,请参阅 有关 C# 语言版本历史记录的文章。

Readonly 字段示例

在此示例中,即使类构造函数向其分配值,也不能更改方法中ChangeYear字段的值year

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;
}

注释

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

有关更多示例,请参阅readonly结构类型文章的实例成员部分。

Ref readonly 返回示例

指示readonlyref return返回的引用无法修改的修饰符。 以下示例返回对源的引用。 它使用 readonly 修饰符来指示调用方无法修改源:

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

返回的类型不需要为 readonly struct. 任何可以返回的类型 ref 也可以由 ref readonly.

Readonly ref readonly 返回值示例

还可以在ref readonly return类型上使用struct实例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# 语法和用法的明确来源。

另请参阅