Skip to content

C# Primary Constructor — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about C# Primary Constructor. We cover key concepts, practical examples, and best practices.

You write a class with a constructor that simply assigns constructor parameters to private fields or properties. That is four extra lines per parameter. Primary constructors let you declare the constructor parameters directly on the type declaration.

Wrong

public class UserService
{
    private readonly IUserRepository _repo;
    private readonly ILogger _logger;

    public UserService(IUserRepository repo, ILogger logger)
    {
        _repo = repo;
        _logger = logger;
    }

    public User GetUser(int id) => _repo.FindById(id);
}

Output: Works. Ten lines of constructor boilerplate for two dependencies.

public class UserService(IUserRepository repo, ILogger logger)
{
    public User GetUser(int id) => repo.FindById(id);
}

Output: Same behavior. The parameters repo and logger are available throughout the class body without explicit field declarations.

Primary constructors work with non-record classes (C# 12+). The parameters are captured and available in all instance members. They can also be used with struct and record struct types.

Prevention

  • Use primary constructors for dependency injection targets.
  • Use primary constructors when the parameters are used in multiple members.
  • Use primary constructors with readonly discipline — capture parameters into fields if you need to mutate them.
  • Use explicit fields when the constructor needs validation logic.
  • Combine primary constructors with required properties for public initialization.
  • Use record types when you need positional deconstruction and value equality alongside primary construction.

Common Mistakes with primary constructor

  1. Misunderstanding that String is [Char] with poor performance for large text operations
  2. Using foldl instead of foldl' causing stack overflow on large lists
  3. Forgetting deriving (Show, Eq) on custom data types needed for debugging

These mistakes appear frequently in real-world CSHARP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

Are primary constructor parameters automatically fields?

No. They are captured variables. The compiler generates a private field for each parameter only if it is used outside the constructor. This is more efficient than manually declaring fields for every parameter.

Can I add validation in a primary constructor?

Yes. Add a constructor body: public class UserService(IUserRepository repo, ILogger logger) { if (repo is null) throw new ArgumentNullException(...); ... }. The parameter scope includes the class body.

What is the difference between primary constructors in records and classes?

In records, primary constructor parameters auto-generate public properties with the same name. In classes, they remain captured parameters (no public property). Use records for data types and classes with primary constructors for services.

Primary constructors are the standard pattern in DodaTech's service layer. For more C# tips, visit DodaTech.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro