DEV Community

Mariem Moalla
Mariem Moalla

Posted on

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(); 
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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>();
Enter fullscreen mode Exit fullscreen mode

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; }
}
Enter fullscreen mode Exit fullscreen mode

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";

Enter fullscreen mode Exit fullscreen mode

These make the property immutable after initialization.

Top comments (0)