OdeToCode IC Logo

C# 6.0 Features Part II : Primary Constructors

Thursday, August 14, 2014

Primary constructors are a feature you’ll find in a few programming languages, including F#, Scala, and Kotlin. A primary constructor allows us to define a constructor for a type and capture the constructor parameters to use in initialization expressions throughout the rest of the type definition.  Here’s one simple example:

public struct Money(string currency, decimal amount) 
{
    public string Currency { get; } = currency;
    public decimal Amount { get; } = amount;
}

Notice how the primary constructor arguments appear inside parentheses just after the type name. The code can then use the arguments in field initializers and property initializers. Common questions about this new syntax revolve around parameter validation, and how primary constructors can work with other explicit constructors. Here’s another example.

public class AddUserCommand(User newUser, User creator) : Command
{
    public AddUserCommand(User newUser)
        : this(newUser, creator: newUser)
    {
    }

    public User NewUser { get; protected set; } = newUser;
    public User Creator { get; protected set; } = Verify.NotNull("creator", creator);
    Guid _creatorId = creator.Id;
}

Once you have a primary constructor, all other constructors must ultimately call into the primary ctor using this(), which makes sense since we always want the primary constructor arguments to be available for initialization (although a struct will still have a non-replaceable default constructor that will initialize all members to default values).

Validation is a bit trickier, but simple validation checks are possible in the initialization expressions.

I really like the primary constructor syntax for components that are managed by an IoC container. Typically these components have a single constructor to accept dependencies, and they need to store the dependencies in a field or property. Validation of the dependencies is not a concern as most containers will (or can) raise an error if a dependency cannot be found.

public class UserController(IUserStorage storage) : Controller
{
    public ActionResult Index()
    {
         // ...
    }

    IUserStorage _storage = storage;
}

The primary constructor syntax means there is a little less code to write for these types of components.