Non-nullable properties in C# 11

powerz

Aleksei Zagoskin

Posted on January 14, 2023

Non-nullable properties in C# 11

After taking a break from blogging, I am excited to be back and try something new. As an experiment, I have decided to focus on writing shorter articles, which hopefully, will allow me to share some of my thoughts, ideas and tips in a more concise and digestible manner. Let's see how it goes. Shall we?

Problem

First, take a look at this simple code:

public record User
{
    public string Name { get; init; }
    public string? Email { get; init; }
}
Enter fullscreen mode Exit fullscreen mode

Nothing fancy here, an immutable record with two properties: Name and Email. At first glance, it may look fine, but the compiler won't like this code:

Program.cs(14, 19): [CS8618] Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
Enter fullscreen mode Exit fullscreen mode

This means that we created an immutable record with a non-nullable property Name, but nothing will stop us from creating a new user and not providing any name at all:

var user = new User { Email = "Sam" };
Enter fullscreen mode Exit fullscreen mode

Solution 1: Assign default!

(Don't do that) Often, to shut the compiler up, programmers assign default values with an exclamation mark to such properties:

public record User
{
    public string Name { get; init; } = default!; // or null! or "" 
    public string? Email { get; init; }
}
Enter fullscreen mode Exit fullscreen mode

Here we simply ask the compiler to ignore the issue, while the problem remains: we are still able to create an instance of that record and forget to assign a value to Name.

💩 Solution 1: Constructor

public record User
{
    public string Name { get; }
    public string? Email { get; init; }

    public User(string name, string? email = default)
    {
        Name = name;
        Email = email;
    }
}
Enter fullscreen mode Exit fullscreen mode

Very boring and verbose code, which at the end of the day does the job. There is no way a developer can forget to pass a value for Namebecause now it's a mandatory constructor parameter.

Solution 2: Positional properties

public record User(string Name, string? Email = default);
Enter fullscreen mode Exit fullscreen mode

In this case whenever we create a new instance of the User type, we have to provide a value for the Name property. Nice and clean.

Solution 3: required modifier

The new keyword required was introduced in C# 11, which can be applied to properties of classes, records and structs. You can find all details as well as information about existing limitations here.

public record User
{
    public required string Name { get; init; }
    public string? Email { get; init; }
}
Enter fullscreen mode Exit fullscreen mode

Problem solved.

I hope it helps and thank you for reading!

Cheers!

💖 💪 🙅 🚩
powerz
Aleksei Zagoskin

Posted on January 14, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related