C# 12 – Primary constructors
Starting from C# 12, it is possible to define a primary constructor within classes and structs. The parameters are placed in parentheses right after the type name.
public class Car(string make)
{
public string Make => make;
}
Code language: C# (cs)
The parameters of a primary constructor have a broad scope. They can be utilized to initialize properties or fields, serve as variables in methods or local functions, and be passed to a base constructor.
By using a primary constructor, it signifies that these parameters are essential for any instance of the type. In case an explicitly written constructor is present, it must utilize the this(...)
initializer syntax to call the primary constructor. This ensures that all constructors effectively assign values to the primary constructor parameters.
In classes, including record class types, the implicit parameterless constructor will not be generated when a primary constructor exists. Conversely, for structs, including record struct types, the implicit parameterless constructor is always created, initializing all fields, including primary constructor parameters, to the 0-bit pattern. If you decide to include an explicit parameterless constructor, it must invoke the primary constructor, allowing you to provide different values for the primary constructor parameters.
The following code demonstrates examples of primary constructors:
public class ElectricCar(string make, int batteryCapacity) : Car(make)
{
public ElectricCar() : this("unknown", 0)
{
}
public int BatteryCapacity => batteryCapacity;
}
Code language: C# (cs)
Within class
and struct
types, primary constructor parameters remain accessible throughout the body of the type. They can be employed as member fields. When utilized, the compiler automatically captures the constructor parameter into a private field with a name generated by the compiler. However, if a primary constructor parameter isn’t used anywhere in the type’s body, no private field is generated. This precautionary rule prevents the inadvertent allocation of two copies of a primary constructor parameter when it’s passed to a base constructor.
In case the type is marked with the record
modifier, the compiler takes a different approach by synthesizing a public property bearing the same name as the primary constructor parameter. For record class types, if the primary constructor parameter shares its name with a base primary constructor, this property becomes a public property of the base record class type and is not duplicated in the derived record class type. It’s important to note that these properties are not generated for non-record types.
One Comment