C#  

Why Readonly Doesn't Make Objects Immutable in C#

When you first encounter the Readonly keyword in C#, it seems straightforward, prevent fields from being reassigned after construction. But once you start applying it to reference types, things get more nuanced.

We’ll break down what Readonly really means, especially when dealing with objects, how it behaves differently with value vs. reference types, and what developers should keep in mind to write safer, cleaner code.

What Does Readonly Actually Do?

In C#, the Readonly keyword:

  • Can be applied to fields.
  • Ensures the field can only be assigned during declaration or inside the constructor of the class/struct.
  • Once assigned, the field can’t point to a different object.
public class User
{
    public string Name { get; set; }
}

public class Account
{
    private readonly User _user = new User();
    public void ChangeUser()
    {
        // This is possible
        _user.Name = "New Name"; 
        // But this will result in compile-time error
        _user = new User(); 
    }
}

Misunderstanding:

A Readonly field of a reference type doesn’t make the object itself immutable, it only means the reference can’t be reassigned. You can still modify the object’s internal state.

Reference Types vs. Value Types with Readonly

Value Types:

readonly int number = 5;
// Compile-time error
number = 10;

With value types (like int, bool, struct), Readonly means you cannot change the value.

Reference Types:

readonly List<string> items = new List<string>();
// Possible
items.Add("Test"); 
// Compile-time error
items = new List<string>();

So, the object can still mutate , it’s the reference that’s locked.

Then, How to Make Reference Types Truly Immutable?

To make an object’s state immutable, you must:

  • Avoid set accessors in properties.
  • Make all fields Readonly.
  • Use init accessors for initialization only.
  • Don’t expose collection fields directly.

Example

public class User
{
    public string Name { get; init; }
}

Radonly with Properties

While Readonly can be used on fields, it cannot be directly used on properties. But you can mimic the behavior using init accessor:

public string Role { get; init; } = "admin";

These make the property immutable after initialization.