Many classes in C# repeat the same pattern of defining a bunch of essential backing fields, then defining a constructor that takes values for those fields and assigns them. This is repetitive code that results in two definitions and an assignment for every parameter/field combination.
C# 12 primary constructors let you declare constructor parameters directly on the type. Those parameters are then in scope throughout the type body and can be used by properties, methods, and initializers.
Code
csharp
class Customer(string firstName, string lastName, DateOnly dateOfBirth)
{
public string FirstName => firstName;
public string LastName => lastName;
public DateOnly DateOfBirth => dateOfBirth;
}csharp
class Customer
{
private string firstName;
private string lastName;
private DateOnly dateOfBirth;
public Customer(string firstName, string lastName, DateOnly dateOfBirth)
{
this.firstName = firstName;
this.lastName = lastName;
this.dateOfBirth = dateOfBirth;
}
public string FirstName => firstName;
public string LastName => lastName;
public DateOnly DateOfBirth => dateOfBirth;
}Notes
- Primary constructor parameters are captured locals, not fields or properties — if any method or lambda in the class body captures a parameter, the compiler emits a hidden backing field and all uses share that field; assigning to it from multiple places can produce surprising mutation bugs