C# 9 introduces init-only properties that allow you to set properties on a class that can only be set once during object initialization.

This is done using a new init accessor introduced in C# 9 as part of a class declaration.

public class Person
{
    public string Name { get; init; }
    public int Age { get; init; }
}

The Person class can now have it's Name and Age properties set once during object initialization and trying to set them again later will result in a C# compiler error.

var person = new Person
{
    Name = "John Doe",
    Age = 18
};

person.Name = "Jane Doe"; // Error CS8852

As expected, you can also use the new init accessor using backing fields just like you can with the set accessor.

public class Person
{
    readonly string _name;
    readonly int _age;

    public string Name { get => _name; init => _name = value; }
    public int Age { get => _age; init => _age = value; }
}

And, of course, you can mix and match using the init accessor and set accessor for properties in the same C# class based on your needs.

public class Person
{
    public string Name { get; set; }
    public int Age { get; init; }
}

Conclusion

We've looked at using the new init-only properties in C# 9 to create immutable instances of a class using object initialization. You can use the init-only properties using auto-implemented properties in C# or using backing fields. You can also mix the set accessor and init accessor in the same class

However, to really appreciate init-only properties in C# 9, pair them with the new record type in C# 9.