C# 9.0: Init-only Properties – Create Immutable Properties Without Constructor Boilerplate

In the previous blog post you learned about C# 9.0 top-level statements. In this blog post you learn about another C# 9.0 feature that is called init-only properties.

In November 2007 Microsoft introduced C# 3.0 with the release of .NET Framework 3.5. C# 3.0 introduced many new concepts, like for example Language Integrated Query (LINQ) syntax. It also introduced the powerful concept of object initializers. They are the foundation for the new init-only properties that are introduced with C# 9.0, so let’s start here with object initializers.

Understand Object Initializers

Let’s say you have a Friend class with the two properties FirstName and LastName:

public class Friend
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Traditionally, you can create a Friend object like below by calling the default constructor and initializing the properties after that:

var friend = new Friend();
friend.FirstName = "Thomas";
friend.LastName = "Huber";

Instead of the three statements as above, you can also use a single statement with an object initializer like in the code snippet below. The object initializer also calls the default constructor and then it initializes the two properties FirstName and LastName by calling their setters:

var friend = new Friend
{
    FirstName = "Thomas",
    LastName = "Huber"
};

Creating Immutable Properties

The problem with object initializers is that they don’t allow you to create immutable properties – at least not before C# 9.0. Immutable properties are properties that you can’t change after you created the object. But in our case, you can change for example the FirstName property of a Friend at any time after you created the Friend object. The snippet below shows this:

var friend = new Friend
{
    FirstName = "Thomas",
    LastName = "Huber"
};

friend.FirstName = "Claudius";

To make the properties immutable, you have to create a constructor as in the snippet below that takes the firstname and lastname as parameters. Note that I’ve removed the setters of the properties, which means the properties can’t be changed after the Friend object was initialized. Defining just a getter with an Auto Property is a so-called get-only Auto Property. It’s a feature that was introduced with C# 6.0 and .NET Framework 4.6 in 2015. Get-only Auto Properties can only be initialized directly or like in the snippet below in the constructor. This is the same logic as with readonly fields, they can also be initialized directly or in a constructor.

public class Friend
{
    public Friend(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public string FirstName { get; }
    public string LastName { get; }
}

With the Friend class defined as above, you can’t change the FirstName or the LastName property after you created the Friend object. Below I try this, you see I get an error that says that the FirstName property is read only.

Now we solved our problem, the properties FirstName and LastName are immutable. But to achieve this, we had to define a constructor.

With C# 9.0 you can create immutable properties without constructor boilerplate: This is possible with the new init-only properties.

The Concept of Init-Only Properties in C# 9.0

In the code snippet below you see a Friend class that looks exactly the same as the Friend class defined in the previous code snippet. And it works exactly the same. But can you spot the little difference?

public class Friend
{
    public Friend(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public string FirstName { get; init; }
    public string LastName { get; init; }
}

The difference is the init keyword used for the Auto Properties. The init keyword is used to define a special kind of set accessor (This means, you get an error if you use init and set in a single Auto Property). These properties are now so-called init-only properties. It means, you can only initialize these properties in the constructor like in the snippet above, or directly like in the snippet below….

public string FirstName { get; init; } = "Thomas";

… or *drumrolls*… in an object initializer. This makes the constructor that we used above unnecessary to define immutable properties. Let’s look at this.


Init-only Properties and Object Initializers

In the snippet below you see a Friend class with init-only properties, and without a constructor. Actually, this Friend class looks exactly the same as the Friend class shown at the beginning of this blog post. The only difference is that we’re using the init keyword instead of the set keyword for our Auto Properties, which makes them init-only properties.

public class Friend
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}

That means, as mentioned before, that you can initialize the properties only in a constructor, directly or in an object initializer. Our Friend class does not have a constructor, so let’s use an object initializer:

var friend = new Friend
{
    FirstName = "Thomas",
    LastName = "Huber"
};

Works like a charm. But now the great thing is that the property cannot be changed after the object was created. And that’s the power of init-only properties. In the screenshot below I try to set the FirstName property after we initialized the Friend object. As you can see, I get an error that says that the init-only property FirstName can only be assigned in an object initializer, constructor or init accessor.

Values for Init-only Properties Are Not Required

Important to mention is that values for init-only properties are not required, they’re optional. You can also set just the properties you want, as you would with normal Auto Properties. For example you could only set the FirstName property of a Friend object as in the snippet below, that’s completely valid. But as we use init-only properties, you have no chance to set the LastName property after this statement, as the properties are immutable:

var friend = new Friend
{
    FirstName = "Thomas",
};

Setting Readonly Fields

As the init accessor of an init-only property is called during object initialization, it is allowed to set readonly fields in the init accessor, exactly in the same way as you could set them in a constructor. This is useful if you want to do checks on the assigned property value. For example assigning null or whitespace makes not much sense for the properties FirstName and LastName. So, you could create the Friend class like below and set readonly fields in the init accessors of the properties. The properties are still immutable, but if you assign null or whitespace in an object initializer – that’s the only way to set these properties of that class as no constructor is defined – you get an ArgumentException.

public class Friend
{
    private readonly string _firstName;
    private readonly string _lastName;

    public string FirstName
    {
        get => _firstName;
        init => _firstName = string.IsNullOrWhiteSpace(value)
            ? throw new ArgumentException("Shouldn't be null or whitespace",
                nameof(FirstName))
            : value;
    }
    public string LastName
    {
        get => _lastName;
        init => _lastName = string.IsNullOrWhiteSpace(value)
            ? throw new ArgumentException("Shouldn't be null or whitespace",
                nameof(LastName))
            : value;
    }
}

Summary

Init-only properties are a powerful feature. They allow you to create immutable properties without defining a constructor that takes the initial property values. While setting init-only properties from a constructor works, you can also set init-only properties with an object initializer, and later you can’t modify them, as they are immutable. This is definitely a very useful feature if you plan to work with immutable data in C#.

Beside init-only properties there’s even more in C# 9.0 to work with immutable data: In the next blog post you learn about record types.

Happy coding,
Thomas

Share this post

Comments (9)

  • Avi Farah Reply

    Thank you

    September 13, 2020 at 1:20 pm
  • Vlad Reply

    Get only properties aren’t read only, thus immutable?

    using System;

    class Person
    {
    private readonly string secondName = “Johnson”;

    public Person()
    {
    FirstName = “John”;
    }
    public string FirstName {get;}
    public string SecondName
    {
    get => secondName;
    }
    }

    class App
    {
    public static void Main()
    {
    Person first = new();
    Person second = new();
    second.FirstName = “Karl”; //error
    second.SecondName = “Ferguson”; //error
    }
    }

    March 13, 2021 at 12:08 pm
    • Thomas Claudius Huber Reply

      They are! :-) Please read the section “Creating Immutable Properties” of the blog post. There I show get-only properties and mention that they are immutable. They have the problem that you can not use them in object initializers, and for this init-only properties exist.

      March 13, 2021 at 1:52 pm
  • Vlad Reply

    Another way to have immutable properties:

    using System;

    class Person
    {
    private string name;

    public string Name
    {
    get => name;
    set => name ??= value;

    }
    }

    class App
    {
    public static void Main()
    {
    Person first = new();
    first.Name = “John”;
    Console.WriteLine($”Name is {first.Name}”); //prints “Name is John”
    first.Name = “Karl”;
    Console.WriteLine($”Name is {first.Name}”); //also prints “Name is John”

    }
    }

    March 13, 2021 at 12:23 pm
    • Thomas Claudius Huber Reply

      No, that’s not really an immutable property. It compiles when you set it, and even at runtime you don’t get an exception. Of course it does not change because of its implementation, but it’s more like a setter implemented in an unexpected way. Think about the developer using that class and property. If they can call a setter without getting a compile error or an exception at runtime, they will assume that the property has that new value after calling the setter. If you don’t throw an exception but also don’t set the value internally, it’s not good and not the expected behavior. On immutable properties, no setter is available, and you would get a compile-time error when you try to set the property.

      March 13, 2021 at 1:49 pm
  • Petr C Reply

    Hi Thomas,
    thanks for nice block post. I’m surprised with one think about init only properties, it could doing them much more cool when it will work, but don’t :(.
    I guess/hope that init only property is full equivalent to constructor parameter (value of them is accessible during constructor execution)

    See code snippet:

    public bool IsInitialized { get; init; }= false;
    public Program()
    {
    if(!IsInitialized) throw new InvalidOperationException(“C# 9.0 init-only sucks! :(“);
    }

    public static void Main()
    {
    new Program { IsInitialized = true };
    }

    See also: https://dotnetfiddle.net/9HQPiV

    May 20, 2021 at 8:02 am
  • Radu Reply

    Quick question please:

    What’s the difference between the field1 and field2 ?

    public class Cls {
    public readonly string field1;
    public string field1 {get; init;}
    }

    What is still unclear for me is:
    1. Why do we need init when it is already readonly there ? Only for serialization ?
    2. Apart of serialization, are not readonly and get/init similar ?

    Kind regards,
    Radu

    September 23, 2021 at 9:46 am
    • Thomas Claudius Huber Reply

      Hi Radu, the second member in your class is not a field, but a property. That’s the difference. So the question is more: Do you want a property or just a readonly field.

      September 28, 2021 at 2:40 pm

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.