Introduction

C# 12, introduced with .NET 8, introduces a long-awaited feature to class and struct definitions: Primary Constructors.

While primary constructors have existed for records since C# 9, now you can use them in regular classes and structs, helping reduce boilerplate and promote more readable, concise code.

Let’s explore how this feature works, when to use it, and how it can simplify your .NET projects.

What Are Primary Constructors?

Primary constructors allow you to declare constructor parameters directly in the class/struct declaration and use them throughout the class, including in field initializations, properties, methods, and more.

This eliminates the need for manual constructor declarations, backing fields, and repetitive code.

Before vs After (C# 11 vs C# 12)

Traditional C# Class (Before)

public class Person
{
    private readonly string _name;

    public Person(string name)
    {
        _name = name;
    }

    public string GetGreeting() => $"Hello, {_name}!";
}

Primary Constructor in C# 12

public class Person(string name)
{
    public string GetGreeting() => $"Hello, {name}!";
}

Boom! One line declaration no constructor body, no field needed!

Real-World Example

Let’s build a class that represents a product with a tax calculation.

Using Primary Constructor

public class Product(string name, decimal price, decimal taxRate)
{
    public decimal FinalPrice => price + (price * taxRate);

    public string GetLabel() => $"{name} - ${FinalPrice:F2}";
}

Usage

var product = new Product("Laptop", 1000m, 0.18m);
Console.WriteLine(product.GetLabel()); // Output: Laptop - $1180.00

Limitations & Notes

Works with Structs Too!

public readonly struct Point(int x, int y)
{
    public double Distance => Math.Sqrt(x * x + y * y);
}

When to Use?

Use primary constructors when,

Conclusion

The addition of Primary Constructors in C# 12 (.NET 8) is a small but mighty feature that helps make your code cleaner, more expressive, and easier to maintain. It's especially useful for lightweight models, services, and utility classes.

By adopting primary constructors, you can embrace the modern C# style focusing more on business logic, and less on plumbing.