Поделиться через


readonly (Справочник по C#)

readonly Ключевое слово — это модификатор, который можно использовать в пяти контекстах:

  • В объявлении поляreadonly указывает на то, что присвоение значения полю может происходить только при объявлении или в конструкторе этого класса. Полю только для чтения можно несколько раз назначить значения в объявлении поля и в конструкторе.

    Поле readonly нельзя изменять после выхода из конструктора. Это правило влечет за собой разные последствия для типов значений и ссылочных типов:

    • Так как типы значений непосредственно содержат их данные, поле, которое является типом readonly значения, является неизменяемым.
    • Ссылочные типы содержат только ссылку на соответствующие данные, а значит поле readonly ссылочного типа будет всегда ссылаться на один объект. Этот объект может быть неизменяемым. Модификатор readonly предотвращает замену значения поля другим экземпляром ссылочного типа. Но этот модификатор не препятствует изменению данных экземпляра, на которое ссылается поле только для чтения, в том числе через это поле.

    Предупреждение

    Внешний видимый тип, содержащий внешне видимое поле только для чтения, которое является изменяемым ссылочным типом, может быть уязвимостью безопасности и может вызвать предупреждение CA2104 : "Не объявляйте только изменяемые типы ссылок".

  • В определении типа readonly struct объект readonly указывает на то, что тип структуры является неизменяемым. Дополнительные сведения см. в описании структуры readonly в статье Типы структур.

  • В объявлении члена экземпляра в типе структуры readonly указывает на то, что член экземпляра не изменяет состояние структуры. Дополнительные сведения см. в разделе о членах экземпляров readonly в статье Типы структур.

  • В возврате метода ref 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 в качестве параметра 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

Вы получите сообщение об ошибке компилятора:

Присваивание значений доступному только для чтения полю допускается только в конструкторе и в инициализаторе переменных.

Члены экземпляров только для чтения

Модификатор можно также использовать readonly для объявления того, что член экземпляра не изменяет состояние структуры.

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

Примечание.

В случае свойства чтения и записи можно добавить readonly модификатор в get метод доступа. Некоторые get методы доступа могут выполнять вычисление и кэшировать результат, а не просто возвращать значение частного поля. readonly Добавление модификатора get в метод доступа гарантирует, что get метод доступа не изменяет внутреннее состояние объекта путем кэширования любого результата.

Дополнительные примеры см. в 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 readonly

Можно ref readonly return также использовать с readonly элементами экземпляра в struct типах:

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#.

Вы также можете ознакомиться с предложениями языковых спецификаций:

См. также