Introduced in C# 12, primary constructors allow you to declare constructor parameters directly on the class or struct declaration, significantly reducing boilerplate code.
Syntax Comparison
Primary Constructor (Modern C# 12+)
public class GameStoreContext(DbContextOptions<GameStoreContext> options) : DbContext(options)
{
// Class members can directly use 'options' here
}Classical Equivalent
public class GameStoreContext : DbContext
{
public GameStoreContext(DbContextOptions<GameStoreContext> options) : base(options)
{
}
}Key Characteristics
-
Scope: Parameters defined in the primary constructor header are in scope for the entire class body.
-
Field Capture (Classes vs. Records):
-
In
recordtypes, primary constructor parameters automatically become public init-only properties. -
In standard
classtypes, they remain parameters (not properties), but the compiler will automatically capture them into private backing fields if they are accessed within methods or properties inside the class.
-
-
Base Class Chaining: You can pass parameters directly to a base class constructor using syntax like
: BaseClass(paramName).public class Person(string name) { public string Name { get; } = name; } public class Employee(string name, string employeeId) : Person(name) { public string EmployeeId { get; } = employeeId; }
In this example, the Employee class uses a primary constructor to accept both name and employeeId. It immediately forwards the name parameter up to the base Person class constructor using : Person(name), while retaining employeeId for its own use.
Common EF Core Usage This pattern is widely adopted in Entity Framework Core for clean, minimal
DbContextdeclarations without redundant constructor bodies.