Making primary constructor parameters read-only
C# 12 introduced a new feature called Primary constructor. This feature allows us to define a constructor directly in the class declaration.
// You can define a constructor directly in the class declaration.
public readonly struct Distance(double dx, double dy)
{
public readonly double Magnitude { get; } = Math.Sqrt(dx * dx + dy * dy);
public readonly double Direction { get; } = Math.Atan2(dy, dx);
}
This feature is useful to define immutable types. However, the compiler does not enforce the immutability of the parameters. For instance, the following code compiles:
public class Foo(double value)
{
// Overriding "value" is ok as it's allowed to update a parameter in C#
// But many people expect the parameter to be read-only like in records
public void UpdateValue(double newValue) => value = newValue;
}
There are multiple ways to solve this issue and be sure the parameter value is not modified.
#Solution 1: using a read-only field
To make the parameter read-only, you can create a readonly
field with the same name as the parameter and assign the value of the parameter to the field. However, this is a lot of boilerplate code:
public class Foo(double value)
{
// readonly field with the same name as the parameter
private readonly double value = value;
// Error CS0191: A readonly field cannot be assigned to
public void UpdateValue(double newValue) => value = newValue;
}
#Solution 2: using a Roslyn analyzer
Another solution is to use a Roslyn analyzer to report all cases where a parameter is assigned. Meziantou.Analyzer provides a diagnostic to report this issue. You can install the package using the following command:
dotnet add package Meziantou.Analyzer
Once the package is installed, the rule MA0143
reports all assignments to the primary constructor parameters in your project or usages as ref
or out
parameters. For instance, the following code will report an error:
#Additional resources
Do you have a question or a suggestion about this post? Contact me!