C# Primary Constructor Class: Syntax and Usage
c# primary constructor class: Learn how to use C# primary constructors for classes: syntax, initialization, dependency injection, and limitations with practical examples.
c# primary constructor class requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
Primary constructors in C# let you declare constructor parameters directly in the class declaration. Instead of writing a separate constructor method, you add parameters after the class name. The compiler captures those parameters and makes them available throughout the class body. This reduces boilerplate for simple initialization patterns.
public class Person(string name, int age) { public string Name { get; } = name; public int Age { get; } = age; }
Here, name and age are primary constructor parameters. They are in scope for the entire class body, so you can use them to initialize properties or pass to base constructors.
How Primary Constructors Differ from Traditional Constructors
With a traditional constructor, you explicitly define a constructor method and assign fields or properties. For a class with several dependencies, that often leads to repetitive code.
public class OrderService { private readonly IOrderRepository _repository; private readonly ILogger<OrderService> _logger; public OrderService(IOrderRepository repository, ILogger<OrderService> logger) { _repository = repository; _logger = logger; } }
With a primary constructor, the same class becomes:
public class OrderService(IOrderRepository repository, ILogger<OrderService> logger) { private readonly IOrderRepository _repository = repository; private readonly ILogger<OrderService> _logger = logger; }
The parameters are in scope for field initializers and property initializers. This is particularly useful for dependency injection, where the constructor only assigns dependencies to private fields.
Capturing Primary Constructor Parameters
Primary constructor parameters are not automatically stored as fields. They are only in scope within the class body. If you need to use them beyond initialization, you must assign them to fields or properties explicitly. This is a key difference from record types, where primary constructor parameters are automatically exposed as properties.
For example:
public class Point(double x, double y) { public double X { get; } = x; public double Y { get; } = y; }
If you want to keep the values for later use, you must store them. If you don't, they are only available during initialization.
Using Primary Constructors with Base Classes
Primary constructor parameters can be passed to a base class constructor. This is done in the class declaration using the base keyword.
public class DerivedClass(int value) : BaseClass(value) { // ... }
This works because the primary constructor parameters are in scope when the base class initializer is evaluated. This can reduce the need for a separate constructor that forwards arguments.
Dependency Injection with Primary Constructors
Primary constructors are a natural fit for dependency injection because they make the dependencies visible directly in the class declaration. Many DI containers can resolve classes with primary constructors without any special configuration, since they treat them like any other constructor.
However, there is a subtlety: if you need to validate dependencies or perform logic before assigning fields, you cannot do that directly in the parameter list. You would need to use a field initializer that calls a method, or fall back to a traditional constructor for more complex setup.
Limitations and Considerations
Primary constructors have some limitations:
- They are not automatically stored as fields; you must assign them if needed.
- You cannot have both a primary constructor and an explicit constructor with the same signature.
- The parameters are in scope for the entire class body, but they are not members of the class. This means you cannot use them in methods unless you capture them.
- They are not supported in all C# versions; you need C# 12 or later.
For simple classes that just store parameters, primary constructors reduce boilerplate. For classes with complex initialization logic, a traditional constructor may be clearer.
When to Use Primary Constructors
Use a primary constructor when:
- The class is simple and only needs to store constructor parameters.
- You are using dependency injection and the constructor only assigns dependencies.
- You want to reduce repetitive code for small data-holding classes.
Avoid primary constructors when:
- You need to perform validation or complex logic in the constructor.
- You need to have multiple constructors with different parameter sets.
- You are targeting an older C# version.
Primary constructors do not introduce any runtime performance overhead. They are a compile-time feature that generates the same IL as a traditional constructor. The decision to use them should be based on code clarity and maintainability, not on runtime behavior.