DEV Community

Aleksei Zagoskin
Aleksei Zagoskin

Posted on • Originally published at zagosk.in on

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!

Oldest comments (3)

Collapse
 
vaishnavravi33 profile image
Ravindra Vairagi

Nice article.

Collapse
 
srplanta profile image
Shafiq Ur Rehman

Great sir, your this article motivated me to switch from C# 10 to C# 11, means from .Net 6 to .Net 7, thanks a lot.

Collapse
 
powerz profile image
Aleksei Zagoskin

Thank you for the feedback, I'm glad you found the article useful!