How to Declare and Use Read-Only Fields in C

In C#, read-only fields allow you to create variables whose values can be assigned only during declaration or within a constructor. This article explains how to declare and initialize read-only fields, how they behave with both value and reference types, and how they differ from compile-time constants.

Declaring a Read-Only Field

To declare a read-only field, add the readonly modifier before the field's data type. A readonly field can be initialized directly at the point of declaration or inside the constructor of the enclosing class.

public class Car
{
    // Initialized at declaration
    public readonly int Wheels = 4;

    // Initialized in constructor
    public readonly string Vin;

    public Car(string vin)
    {
        Vin = vin; // Allowed
    }

    public void ChangeVin(string newVin)
    {
        // Vin = newVin; // Compile error: A readonly field cannot be assigned to here
    }
}

Static Read-Only Fields

If you want a read-only field that belongs to the type itself rather than an instance, combine the static and readonly keywords. Static read-only fields can be initialized at declaration or inside a static constructor.

public class Configuration
{
    public static readonly DateTime AppStartTime;

    static Configuration()
    {
        AppStartTime = DateTime.UtcNow;
    }
}

Key Rules for Read-Only Fields

  1. Assignment Timing: Values must be assigned either at the point of declaration or inside the constructor (instance constructors for instance fields, static constructors for static fields).
  2. Context Restriction: You cannot reassign a read-only field from outside the class or from an instance method inside the class.
  3. Runtime Evaluation: Unlike compile-time constants, the value of a readonly field is determined at runtime, allowing you to pass values into constructors dynamically.

Difference Between readonly and const

Feature readonly const
Evaluation Time Runtime Compile-time
Assignment Locations Declaration or Constructor Declaration only
Types Allowed Any type Primitive types, strings, enums, null
Static by Default No (requires static keyword) Yes (implicitly static)

Read-Only Fields with Reference Types

When using readonly with a reference type, only the memory address (reference) is immutable. The properties and data within the referenced object can still be modified.

public class Team
{
    public readonly List<string> Members = new List<string>();

    public void Modify()
    {
        // Allowed: Modifying the object's state
        Members.Add("Alice");

        // Error: Cannot reassign the reference
        // Members = new List<string>(); 
    }
}

To make the contents of a collection or complex object fully immutable, use read-only collections (such as ReadOnlyCollection<T> or ImmutableArray<T>) rather than relying solely on the readonly keyword.