Introduction
C# is constantly evolving to make developers' lives easier by reducing boilerplate code and improving readability. One of the most useful features introduced in C# 12 is Primary Constructors. This feature helps you write cleaner, shorter, and more maintainable code, especially when working with classes and structs that mainly exist to hold data.
If you have worked with constructors before, you already know that writing repetitive assignments can feel unnecessary and time-consuming. Primary constructors solve this problem by allowing you to define constructor parameters directly in the class declaration.
In this article, we will understand what primary constructors are, how they work, and why they are beneficial in real-world development.
What Are Primary Constructors in C# 12?
Primary constructors allow you to declare constructor parameters directly in the class or struct definition instead of writing a separate constructor body.
Traditional Constructor Example
Before C# 12, you would write code like this:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
Here, you manually assign values inside the constructor.
Primary Constructor Example
With C# 12, the same code becomes:
public class Person(string name, int age)
{
public string Name { get; set; } = name;
public int Age { get; set; } = age;
}
As you can see, the constructor parameters are defined directly in the class declaration, reducing extra code.
How Primary Constructors Work
Primary constructor parameters are available throughout the class body. You can use them to initialize fields, properties, or even use them inside methods.
Example with Fields
public class Employee(string name, double salary)
{
private readonly string _name = name;
private readonly double _salary = salary;
public void Display()
{
Console.WriteLine($"Name: {_name}, Salary: {_salary}");
}
}
Example with Logic
public class Product(string name, double price)
{
public string Name { get; } = name;
public double Price { get; } = price > 0 ? price : 0;
}
This allows you to add validation or logic directly during initialization.
Key Benefits of Primary Constructors
1. Less Boilerplate Code
Primary constructors remove the need to write repetitive constructor assignments. This makes your code shorter and easier to maintain.
Instead of writing multiple lines for assigning values, everything is handled in a single line.
2. Improved Readability
When you define parameters at the top of the class, it becomes immediately clear what data the class depends on.
This improves code clarity, especially for new developers or when reviewing code.
3. Better Maintainability
With fewer lines of code, there are fewer chances of mistakes such as missing assignments or incorrect variable usage.
Updating code also becomes easier because everything is centralized.
4. Encourages Clean Code Practices
Primary constructors promote a clean and modern coding style. They align well with immutable objects and help developers follow best practices.
5. Works Well with Dependency Injection
In modern applications, especially in ASP.NET Core, dependency injection is widely used.
Primary constructors make it easier to inject dependencies directly:
public class OrderService(ILogger<OrderService> logger)
{
private readonly ILogger<OrderService> _logger = logger;
}
This makes the code more concise and easier to understand.
6. Supports Both Classes and Structs
Primary constructors are not limited to classes. You can also use them with structs.
public struct Point(int x, int y)
{
public int X { get; } = x;
public int Y { get; } = y;
}
This makes them very flexible for different use cases.
When Should You Use Primary Constructors?
Primary constructors are best suited for:
However, if your constructor contains complex logic, multiple overloads, or heavy processing, a traditional constructor might still be a better choice.
Limitations of Primary Constructors
While primary constructors are powerful, they do have some limitations:
Not ideal for complex initialization logic
Can reduce readability if overused in large classes
May not replace all constructor scenarios
Understanding when to use them is important for writing balanced and maintainable code.
Real-World Example
Let’s look at a practical example:
Without Primary Constructor
public class UserService
{
private readonly IUserRepository _repository;
public UserService(IUserRepository repository)
{
_repository = repository;
}
}
With Primary Constructor
public class UserService(IUserRepository repository)
{
private readonly IUserRepository _repository = repository;
}
This version is shorter and cleaner, especially in large projects.
Conclusion
Primary constructors in C# 12 are a modern feature that helps reduce boilerplate code, improve readability, and encourage clean coding practices. They are especially useful for simple classes, data models, and dependency injection scenarios.
By using primary constructors wisely, you can write cleaner, more maintainable, and professional-quality C# code. However, it is important to balance their usage and not force them into scenarios where traditional constructors are more suitable.
In short, primary constructors are a step forward in making C# more developer-friendly and efficient.