readonly
The readonly
keyword is a modifier that can be used in three contexts:
-
In a field declaration,
readonly
indicates that assignment to the field can only occur as part of the declaration or in a constructor in the same class. -
In a
readonly struct
definition,readonly
indicates that thestruct
is immutable. -
In a
ref readonly
method return, thereadonly
modifier indicates that method returns a reference and writes are not allowed to that reference.
The final two contexts were added in C# 7.2.
Readonly field example
In this example, the value of the field year
cannot be changed in the method ChangeYear
, even though it is assigned a value in the class constructor:
class Age
{
readonly int year;
Age(int year)
{
this.year = year;
}
void ChangeYear()
{
//year = 1967; // Compile error if uncommented.
}
}
You can assign a value to a readonly
field only in the following contexts:
- When the variable is initialized in the declaration, for example:
public readonly int y = 5;
- In an instance constructor of the class that contains the instance field declaration.
- In the static constructor of the class that contains the static field declaration.
These constructor contexts are also the only contexts in which it is valid to pass a readonly
field as an out or ref parameter.
The readonly
keyword is different from the const keyword. A const
field can only be initialized at the declaration of the field. A readonly
field can be initialized either at the declaration or in a constructor. Therefore, readonly
fields can have different values depending on the constructor used. Also, while a const
field is a compile-time constant, the readonly
field can be used for runtime constants as in the following example:
public static readonly uint timeStamp = (uint)DateTime.Now.Ticks;
class SampleClass
{
public int x;
// Initialize a readonly field
public readonly int y = 25;
public readonly int z;
public SampleClass()
{
// Initialize a readonly instance field
z = 24;
}
public SampleClass(int p1, int p2, int p3)
{
x = p1;
y = p2;
z = p3;
}
public static void Main()
{
SampleClass p1 = new SampleClass(11, 21, 32); // OK
Console.WriteLine($"p1: x={p1.x}, y={p1.y}, z={p1.z}");
SampleClass p2 = new SampleClass();
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
*/
}
In the preceding example, if you use a statement like the following example:
p2.y = 66; // Error
you will get the compiler error message:
A readonly field cannot be assigned to (except in a constructor or a variable initializer)
Readonly struct example
The readonly
modifier on a struct
definition declares that the struct is immutable. Every instance field of the struct
must be marked readonly
, as shown in the following example:
public readonly struct Point
{
public double X { get; }
public double Y { get; }
public Point(double x, double y) => (X, Y) = (x, y);
public override string ToString() => $"({X}, {Y})";
}
The preceding example uses readonly auto properties to declare its storage. That instructs the compiler to create readonly
backing fields for those properties. You could also declare readonly
fields directly:
public readonly struct Point
{
public readonly double X;
public readonly double Y;
public Point(double x, double y) => (X, Y) = (x, y);
public override string ToString() => $"({X}, {Y})";
}
Adding a field not marked readonly
generates compiler error CS8340
: "Instance fields of readonly structs must be readonly."
Ref readonly return example
The readonly
modifier on a ref return
indicates that the returned reference cannot be modified. The following example returns a reference to the origin. It uses the readonly
modifier to indicate that callers cannot modify the origin:
private static readonly Point origin = new Point(0, 0);
public static ref readonly Point Origin => ref origin;
The type returned doesn't need to be a readonly struct
. Any type that can be returned by ref
can be returned by ref readonly