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

Readonly 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.

HostForLIFE ASP.NET Core 9.0 Hosting

European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.