In this article, we’ll dive into one of the cool new features of C# 9.0: the Init keyword.

First, we’ll take a closer look at what this feature is. Then, we’ll explore how the Init keyword works and how we can incorporate it into our projects.

To download the source code for this article, you can visit our GitHub repository.

Let’s dive in!

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

What Is the Init Keyword in C#?

C# 9.0 introduced a new init keyword, which acts like an accessor method similar to get and set. This feature allows us to assign values to read-only properties only during the initialization of the object. We can use this feature to create immutable objects that require a specific set of values during their creation, and those values should remain unchanged during the object’s lifetime.

Because we can call the init accessors only during object creation, we can also initialize readonly fields.

How Does Init Work in C#?

To better illustrate how init works, let’s create a class representing a city:

public class City
{
    public string Name { get; init; }
    public double Latitude { get; init; }
    public double Longitude { get; init; }

    public City(string name, double latitude, double longitude)
    {
        Name = name;
        Latitude = latitude;
        Longitude = longitude;
    }
}

We create a City class that has three properties Name,Latitude, and Longitude. They all have two accessors – get and init. We also have a constructor that takes in three parameters.

Now, let’s create a city:

var city = new City("Tokyo", 139.839478, 35.652832);

Console.WriteLine($"{city.Name}: {city.Latitude}, {city.Longitude}");

In our Program class, we create an instance of our City class by passing Tokyo as the Name and the corresponding Latitude and Longitude. Then, we print our city to the console:

Tokyo: 139.839478, 35.652832

Let’s try to change the latitude:

city.Latitude = 104.435261;

When we do that and try to build or run our solution, we get:

Init-only property or indexer 'City.Latitude' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor.

The application won’t compile if we assign any Init-only properties outside of object initialization. This means that when we use init, we create truly immutable properties. For another option for creating immutable objects, you might also want to look at Records in C# as well.

Init vs Private Set in C#

We might have noticed that init and private set are very similar and wonder what is the difference between them. We can use both keywords to create read-only properties, but they have a subtle difference between them. 

Let’s update our City class:

public class City
{
    public string Name { get; private set; }
    public double Latitude { get; init; }
    public double Longitude { get; init; }

    public City(string name, double latitude, double longitude)
    {
        Name = name;
        Latitude = latitude;
        Longitude = longitude;
    }

    public void ChangeName(string name)
    {
        Name = name;
    }
}

We update the accessor of the Name property from init to private set. As it makes more sense to change a city’s name than its coordinates, we add the ChangeName method that takes a string parameter and updates the name of our city.

Let’s try updating the Name property directly:

city.Name = "Edo";

When we try to change the name of Tokyo to Edo (its old name), the compiler is not happy:

The property or indexer 'City.Name' cannot be used in this context because the set accessor is inaccessible

This is because properties with the private set accessor can only be modified from inside the class:

city.ChangeName("Edo");

Console.WriteLine($"{city.Name}: {city.Latitude}, {city.Longitude}");

Here, we use the ChangeName method to change the name of our city. This works and our code compiles:

Edo: 139.839478, 35.652832

We successfully changed the name!

If we try the same approach with init, our code will not compile. We will get the same error as when we tried to update Latitude in our Program class. This is the main difference between init and private setproperties marked as init can’t be changed once the object is initialized, whereas those marked with private set can be updated from inside the object after its creation.

Conclusion

In this article, we learned that by marking properties with the init keyword, we can make it clear that they should not be modified after initialization. In comparison, we can also use the private set keyword to create read-only properties, but with the ability to modify them from within the class. Deciding which one to use depends on the level of immutability you need.

If we need truly immutable properties and fields, we should use init. If we need read-only properties that can be updated from inside the class, we should use private set. Understanding the difference between the two can help us write more robust and maintainable code.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!