We last mentioned primary constructors in 2014 when it was removed from the candidate list for C# 6 and VB 12. Late last year, Primary Constructors reappeared as proposal #2691, which is now a candidate for C# 9.
The basic idea behind a primary constructor is it reduces the amount of boilerplate code needed to initialize a class.
class C(string x)
{
public string X
{
get => x;
set {
if (value == null)
throw new NullArgumentException(nameof(X));
x = value;
}
}
}
compiles as…
class C
{
private string _x;
public C(string x)
{
_x = x;
}
public string X
{
get => x;
set {
if (value == null)
throw new NullArgumentException(nameof(X));
x = value;
}
}
}
Richard Gibson summarizes how they would be useful:
A quick sample taken from our codebase of 30 classes shows that 22 of them (73%) had an explicit constructor defined and of those 21 (> 95%) did nothing other than set private readonly fields) are dumb, tedious, can be auto generated, are rarely read--normally skipped over--by humans (because they're usually so dumb) and are therefore a surprisingly common source of bugs.
He goes on to explain those bugs usually come down to accidentally assigning a constructor parameter to the wrong field.
This concept heavily overlaps with the records proposal we reported on in Easier Immutable Objects in C# and VB. MgSam writes,
This proposal seems completely incompatible with the current record proposal. And I disagree with the statement in the proposal saying this is more widely useful than records. I think this saves a little bit of boilerplate- records (and related features of auto-generating GetHashCode, Equals, ToString) can potentially save a ton of boilerplate in a lot of scenarios.
HaloFour also weighed in on the topic:
With the way records have been proposed for C# they include symmetric construction and deconstruction as well as identify based on a specific set of properties. Primary constructors get you all of that in one parameter list given that the parameters are also properties and that list gives you an order in which those properties can be deconstructed.
C# records, as they have been proposed, are more like Scala case classes or F#'s single case unions, and both languages define the construct by how they are constructed.