C# allows writing code with positional or nominal code style. Using positional code style, constructors can be used. Object initializer belong to the nominal category. So far the nominal category was restricted because it required writable properties. This can change with C# 9.

Positional Creation
Positional creation is the traditional coding style we use since the first version of C#. We use constructors to initialize an object. With inheritance, the constructor initialization can call into the constructor of the base class. Objects are creating passing parameters to the constructor:
public class Person
{
public string FirstName { get; }
public string LastName { get; }
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
}
public class Racer : Person
{
public string RacingTeam { get; }
public Racer(string firstName, string lastName, string racingTeam)
: base(firstName, lastName)
{
RacingTeam = racingTeam;
}
}
Person p = new Racer("Charles", "Leclerc", "Ferrari");
While positional creation was possible with C# 1, the code I’ve used in this sample doesn’t compile with C# 1. We didn’t have auto properties at that time and had to write more lines of code for full properties.
Nominal Creation
With nominal creation the code can be reduced by a few code lines. Instead of defining constructors, an object initializer can be used.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Racer : Person
{
public string RacingTeam { get; set; }
}
Person p = new Racer { FirstName = "Charles", LastName = "Leclerc", RacingTeam = "Ferrari" };
Object initialization comes with important restrictions. The object initializer is just syntax sugar. Behind the scenes, the object initializer sets properties – after the constructor was invoked. It’s not possible to create immutable types that way. The properties need to have a set accessor, otherwise the object initializer cannot be used. That’s why often I need to use the positional creation style, and I’m happy when frameworks support non-default constructors (like EF Core).
C# 9 Nominal Creation
The new C# 9 records feature is based on the nominal features. To create immutable types, this requires changes. The plan with C# 9 is to support init-only properties by defining the init accessor. These properties can be set after the constructor was running – with the initialization of the object using an object initializer:
public class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
public class Racer : Person
{
public string RacingTeam { get; init; }
}
Person p = new Racer { FirstName = "Charles", LastName = "Leclerc", RacingTeam = "Ferrari" };
init only members can be initialized at the point of object creation but become readonly after object creation has completed.
Of course, sometimes more complex validation is required that cannot be done with single properties, e.g. using a combination of multiple properties. With single properties, the init accessor can have a code block like we know from the traditional property accessors, so simple checks can be done. For checking multiple properties, the new validator with the init code block can be used:
public class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
init
{
if (FirstName.Length + LastName.Length > 52)
{
throw new Exception("...");
}
}
}
C# 9 Factories and With Expressions
To create new objects from existing ones, copy constructors and With factory methods can be used. In the code snippet, the Person class defines a copy constructor that returns a new person. The With method is marked as a factory method and invokes the copy constructor. With the Racer class that derives from Person, a copy constructor is defined that in turn invokes the copy constructor of the base class. This class overrides the With method of the base class to return a Racer. Overriding the method you can see that the return type is changed from a Person to a Racer. This is not possible with C# 8, but there’s a plan for C# 9 to allow this.
After creating the first racer, using the same data the second racer is created using the With method. Because this method is a factory method, the object initializer can be used to make some changes.
public class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
protected Person(Person that) => (FirstName, LastName) = (that.FirstName, that.LastName);
[Factory] public virtual Person With() => new Person(this);
}
public class Racer : Person
{
public string RacingTeam { get; init; }
protected Racer(Racer that) : base(that) => RacingTeam = that.RacingTeam;
[Factory] public override Racer With() => new Racer(this);
}
Person p1 = new Racer { FirstName = "Charles", LastName = "Leclerc", RacingTeam = "Ferrari" };
Person p2 = p1.With() { FirstName = "Arthur" };
C# 9 also allows using a with expression instead of a method invocation:
Person p3 = p1 with { FirstName = "Arthur" };
C# 9 Records
Instead of defining a copy constructor and a With method, C# 9 can create an implementation with the new records syntax. Defining the class, record can be added to automatically create code for a copy constructor, a With method, equality comparisons, and more:
public record class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
public record class Racer : Person
{
public string RacingTeam { get; init; }
}
Person p1 = new Racer { FirstName = "Charles", LastName = "Leclerc", RacingTeam = "Ferrari" };
Person p2 = p1 with { FirstName = "Arthur" };
Take away
Before C# 9, nominal creation had a limited scope – it was not possible to use this syntax for immutable types. C# 9 changes this, and I think this makes nominal creation the preferred syntax style.
I’m thinking on changing the code in the upcoming edition of my Professional C# book for nominal creation, and reduce positional creation to a minimum, just to keep it so existing code can be read as well. What do you think?
If you’ve read this far, consider buying me a coffee which helps me staying up longer and writing more articles.
Enjoy learning and programming!
Christian
Links
Init Only Setters – C# Proposal
Records as a collection of features
C# Language Design Meeting from April 6th, 2020 for init-only members
More information on C# and programming .NET Core applications is in my book Professional C# 7 and .NET Core 2.0, and in my workshops.
Change / Chance Image ID 115654656 © Fotoaccount | Dreamstime.com







Leave a comment