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.
Let’s dive in!
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 set
– properties 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.