readonly (C# 参考)

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

  • 字段声明中readonly 指示对字段的赋值只能作为声明的一部分或在同一类的构造函数中发生。 可以在字段声明和构造函数中多次分配和重新分配只读字段。

    readonly 构造函数退出后,无法对字段进行赋值。 此规则对值类型和引用类型有不同的影响:

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

    警告

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

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

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

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

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

注释

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

可以在结构类型文章的实例成员部分找到更多示例readonly

Ref readonly 返回示例

指示返回引用不能修改的readonly修饰符在ref 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 返回值示例

还可以对readonly类型上的struct实例成员使用 Aref readonly return

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# 语法和用法的明确来源。

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

另请参阅