Required non-initialized non-nullable properties

April 19th 2024 C#

With the introduction of nullable reference types, null-forgiving operator is often used to avoid compiler warnings on non-nullable properties, which are initialized by library code. The required modifier can be a good alternative to that.

CsvHelper is a library where you can encounter such an issue. When following the documentation, you will create a simple class with a property for each column in the CSV file. For example:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

With nullable reference types enabled, this will result in a compiler warning:

Warning for a non-initialized non-nullable property

The warning can be fixed by initializing the property with a non-null value. Or alternatively, with a null value followed by the null-forgiving operator:

public class Person
{
    public string FirstName { get; set; } = null!;
    public string LastName { get; set; } = null!;
}

This way, the property value is still null, but the compiler doesn't complain anymore.

That's perfectly fine, when the class instances are generated by CsvHelper reading a CSV file. If the corresponding column is present in the file, The library will assign a non-null value to the property. If there's no corresponding column in the file, the library will throw an exception.

However, when creating class instances from code instead, the compiler will not warn you if you don't initialize the properties. And your instance will have non-nullable properties with a null value. You're using nullable reference types to avoid this exact scenario.

You could create a constructor with parameters for all non-nullable properties (or use a record with a primary constructor) instead of using the null-forgiving operator. CsvHelper supports this (although it can make configuring the mapping with attributes more tricky). But not all libraries do.

C# 11 introduced the required modifier, which allows you to not initialize all the non-nullable properties:

public class Person
{
    public required string FirstName { get; set; }
    public required string LastName { get; set; }
}

This also works perfectly fine with CsvHelper (and similar libraries). But in contrast to using the null-forgiving operator, you'll get a compiler error if you fail to initialize such properties when instantiating the class from code:

Error for a non-initialized required property

You can find a small sample project in my GitHub repository. The final commit shows the use of the required modifier. The one before that uses null-forgiving operator instead.

While null-forgiving operator can be used to resolve nullable warnings, it's usually a bad idea that can lead to hidden bugs in the code. In this post, I've shown how the required modifier can sometimes be used instead, resulting in safer code.

Get notified when a new blog post is published (usually every Friday):

Copyright
Creative Commons License