C# 12 introduced primary constructors, a feature that lets you define a constructor directly in the class declaration.
C#
// 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);
}
Primary constructors are useful for defining immutable types. However, the compiler does not enforce parameter immutability. For example, the following code compiles without errors:
C#
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 ensure primary constructor parameter values are not modified.
#Solution 1: using a read-only field
To make a parameter read-only, create a readonly field with the same name and assign the parameter value to it. However, this approach adds boilerplate code:
C#
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. Meziantou.Analyzer provides a diagnostic that reports all assignments to primary constructor parameters. Install it with:
Shell
dotnet add package Meziantou.Analyzer
Once installed, rule MA0143 reports all assignments to primary constructor parameters, as well as usages as ref or out arguments. The following code will trigger an error:

#Additional resources
Do you have a question or a suggestion about this post? Contact me!