Primary constructors adds class parameters in C# 12

Published: Friday 13 October 2023

Primary constructors is a new C# 12 feature that has the ability to define parameters for a type, such as a class.

It overrides the default parameterless initalisation of a class as the parameters need to be included when initalising a class.

Default initalisation behaviour of a class

A class that doesn't have a constructor can be initialised without any parameters. An example can be seen here:

public class Employee {

}

var employee = new Employee();

The Employee class clearly doesn't have any defined constructors inside it so a default parameterless constructor is created and can be used to initalise the class.

Adding parameters to constructors

To override the default behaviour of class initalisation, we can explictly define constructors with parameters.

However, these parameters are only available inside the constructor. If we wish to use the parameters values inside the class, we would have to define separate fields and add the parameters values to these fields.

public class Employee {
	private readonly TimeSpan _startTime;
	private readonly TimeSpan _finishTime;
	
	public Employee(TimeSpan startTime, TimeSpan finishTime) {
		_startTime = startTime;
		_finishTime = finishTime;
	}
}

This adds a lot of code bloat to the class, so how can we reduce that?

Introducing primary constructors

Primary constructors allow us to add parameters to the class. As a result, the values from these parameters are available throughout the class and can be used in properties, fields and methods.

In this example, we are passing the startTime and finishTime as parameters in the Employee class and then using the startTime parameter in the GetStartTime method.

public class Employee(TimeSpan startTime, TimeSpan finishTime) {

	public TimeSpan GetStartTime() {
		return startTime;
	}

}

Adding constructors with primary constructors

With primary constructors, it changes the way we have to add a constructor as we need to include the parameter values. If we don't, we get the following build exception:

A constructor declared in a type with parameter list must have 'this' constructor initializer.

To do that, we include the this keyword and add the values for the parameters.

public class Employee(TimeSpan startTime, TimeSpan finishTime) {

	public Employee() : this(new TimeSpan(9,0,0), new TimeSpan(17,0,0)) {
	
	}

	public TimeSpan GetStartTime() {
		return startTime;
	}
	
}

Dependency injection support

Primary constructors work with in the same way with dependency injection. Rather than having to add each service as a constructor parameter and setting the parameter value to a field, we can add the service as a class parameter.

This means that we can use the service throughout the class like in a method.

[Route("api/employee")]
public class EmployeeController(IEmployeeService _employeeService) : Controller {

	[HttpGet]
	public IActionResult Index() {
		return Ok(_employeeService.GetNewEmployee().GetStartTime());
	}

}

Watch the video

Watch our primary constructor video where we show you how to add primary constructors to a class and how it works with dependency injection.

Are primary constructors a good addition?

There is a lot of code bloat needed to use constructor parameter values throughout the class.

Primary constructors significantly reduces the amount of code needed to do this and therefore is going to help with tidy code.

Therefore, we think it's a great addition in C# and we look forward to using it in .NET 8 applications.