readonly (C# Reference)

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 the struct is immutable.
  • In a ref readonly method return, the readonly 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.

Note

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 Usage()
    {
        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:

The left-hand side of an assignment must be an l-value

which is the same error you get when you attempt to assign a value to a constant.

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

C# Language Specification

For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.

See Also

C# Reference
C# Programming Guide
C# Keywords
Modifiers
const
Fields