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#.
Вы также можете ознакомиться с предложениями языковых спецификаций: