There's a lot of different ways to create an object in C# and set its state. There are the constructor, the setters on properties, and the object initializers introduced in C# 7.0. Although we have all those methods to create an object, it feels like something is missing. How do you construct an object and make it immutable after creation? Before C# 9.0, you had to do something like this:

public class Order
{
    public Order(int number)
    {
        this.Number = number;
    }
    public int Number { get; }
}

Get-only properties make sure the value can only be set during the object construction.

Construction vs. Initialization

There's an essential distinction in .NET between construction and initialization. They are two different creation phases of an object. They can be combined using an object initializer which is mostly just a nicer way to affect properties while constructing an object. Object initializer are heavily used in the industry because they simplify the initialization of an object's properties with a clean and light syntax. However, you'll soon find that they are not compatible with get-only properties, which could be annoying. Get-only properties are backed by a readonly field, which can only be set in the construction phase using a constructor.

If you are in this situation, you then have two choices:

  • You make your properties settable and break immutability.
  • Or, you make the property mandatory for construction by adding it as a constructor's parameter, and use the constructor instead of an objet initializer.

Something was missing

Both options are quite bad, and you shouldn't have to choose between proper immutability or code usability/maintainability. Fortunately, init-only properties come to the rescue in C# 9.0 to address this very issue and give us the best of both worlds.

The init keyword

To make it happen, the C# team had to introduce a new keyword to the language; the init keyword. This keyword can only be used as a replacement for the set keyword. init is a simple keyword that will make a property settable ONLY at initialization and construction. Thus it enables us to set a property through an object initializer without making it mandatory for construction. The property is then either set or not and can never be changed afterward.

public class Order
{
    public int Number { get; init; }
}

public void SomeMethod()
{
    var o = new Order
    {
        Number = 1,
    };

    o.Number = 2; // Compilation Error
}

It's also good to know that it's possible to declare a method body for the init keyword. As the compiler will enforce that the init property can only be called at initialization, it's possible to manipulatereadonly fields in the method body.

public class Order
{
    private readonly int _number;

    public int Number
    {
        get
        {
            return this._number;
        }

        init
        {
            this._number = value;
        }
    }
}

When to use

You are probably a bit confused right now about when and where to use that new feature. Depending on your use case, here's a quick recap that should help you decide. If your property is:

Required Optional
Immutable Constructor parameter
+ Get-only property
Object initializer
+ Init-only property
Mutable Constructor parameter
+ Get/Set property
Get/Set property

Constructors should be used to enforce required values, and init-only properties should be used to enforce immutability on optional properties.

Wrapping up

init-only properties are another great addition to the language that will most likely come very handy. This feature is also the foundation of other significant improvements to language like primary constructors and records. If you want to know more about C# 9.0 check out my getting started article.

You can also find all the above code examples and much more on my GitHub repo