This post discusses the somewhat new keyword introduced in C# 9 with .NET 5, which is the init keyword.
In a previous post in which we discussed about the Null Object Pattern, we discussed of a hackish approach to make sure that the default properties cannot be changed.
Please note that the code snippets from this post have been run in LinqPad so they can be used as is, to run them in Visual Studio, you might be required to make small changes.
In this post, we will discuss about the somewhat new keyword that was introduced in C# 9 with .NET 5, and that is the init
keyword.
How Does It Work?
This keyword will allow us to create immutable objects (at least in regards to the properties that are marked with init
) so that we can make sure no one can change the value later on.
So how do we use this keyword? Well, this keyword is to be used instead of the set
keyword when declaring properties as follows:
class TestClass1
{
public int TestClass1IntProperty { get; set; }
}
class TestClass2
{
public int TestClass1IntProperty {get; init; }
}
And the usage of these properties can be seen as follows:
void Main()
{
TestClass1 test1 = new TestClass1
{
TestClass1IntProperty = 42
};
test1.TestClass1IntProperty = 43;
TestClass2 test2 = new TestClass2
{
TestClass2IntProperty = 42
};
test2.TestClass2IntProperty = 43;
}
Because this keyword is used instead of the set
keyword for properties, this means we could also have classes declared with only some of the properties being marked with init
for immutability purposes like so:
class TestClass3
{
public int TestClass3IntProperty { get; set; }
public int TestClass3IntProperty2 { get; init; }
}
Also, because we’re talking about properties, we are also talking about generated methods with backing fields, as such, we could run custom code when setting the value for a property but only when initializing the instance like so:
class TestClass4
{
private int _testClass4IntProperty;
public int TestClass4IntProperty
{
get => _testClass4IntProperty;
init => _testClass4IntProperty = value;
}
private int _testClass4IntProperty2;
public int TestClass4IntProperty2
{
get { return _testClass4IntProperty2; }
init { _testClass4IntProperty2 = value; }
}
}
So far so good, not too much to explore on this front, though the feature is very powerful for designing safer code, but let’s look at some other scenarios.
Things to Keep in Mind
Reference Properties Only Keep a Reference
Let’s say we have the following class:
class TestClass5
{
public int TestClass5IntProperty { get; set; }
}
class TestClass6
{
public TestClass5 TestClass6RefProperty { get; init; }
}
Just like if we were to declare a field as readonly
or we have a property with only a getter, this only refers to the instance held inside that field/property, as such, we can still change the non-immutable properties of instances that are referenced by an immutable field/property:
void Main()
{
TestClass6 test = new TestClass6
{
TestClass6RefProperty = new TestClass5
{
TestClass5IntProperty = 42
}
};
test.TestClass6RefProperty.TestClass5IntProperty = 445;
test.TestClass6RefProperty = new TestClass5 { TestClass5IntProperty = 13 };
}
Reflection Can Still Bypass the Restriction
Let us have a look at the following code and explain why it works, we will be making use of the TestClass2
we defined before for brevity’s sake.
void Main()
{
TestClass2 test = new TestClass2
{
TestClass2IntProperty = 42
};
Console.WriteLine(test.TestClass2IntProperty);
PropertyInfo setPropertyInfo = test.GetType().GetProperty
(nameof(TestClass2.TestClass2IntProperty));
setPropertyInfo.SetValue(test, 512);
Console.WriteLine(test.TestClass2IntProperty);
}
If we run the code in the example above, we will see that we managed to change the value and have no compilation error, so just because the developer isn’t allowed to directly change the value of an immutable property, that doesn’t mean that they cannot.
I believe the reason this works is that many frameworks rely upon reflection to do their work. Frameworks like Entity Framework and other ORMs, serialization frameworks, and so on.
I hope you enjoyed this post and in the next one, we will be having a look at records.