Search code examples
c#.net-6.0c#-10.0

.NET 6 What is the best way to make properties required and non-null in records


I searched for an answer for it and couldn't find a clear answer. And yes, I know that similar questions exist everywhere. I hope I can get an answer here.

Let's assume I have a Person class with 2 properties (FirstName, MiddleName). FirstName is required & MiddleName is optional.

I want the FirstName property to always have non-nullable data.

Here are some options I think of (but none of them seems to be perfect).

One optional way would be to use the short syntax of records:

// FirstName might be null (bad)
// MiddleName is optional (good)
public record Person(string FirstName, string? MiddleName);

Another way would be to use the null-forgiving operator, but still the same problem.

// FirstName might be null (bad)
// MiddleName is optional (good)
public record Person
{
    public string FirstName { get; init; } = null!;

    public string? MiddleName { get; init; }
}

The old option would be to check the input in the constructor:

// FirstName is required and will always have some data (good)
// MiddleName is optional (good)
// Long syntax (bad)
public record Person
{
    public string FirstName { get; init; }

    public string? MiddleName { get; init; }

    public Person(string firstName, string? middleName)
    {
        // Probably it would be better to check if it is NullOrWhiteSpace.
        ArgumentNullException.ThrowIfNull(firstName);

        FirstName = firstName;
        MiddleName = middleName;
    }
}

If the last option is the way to enforce a non-null value, then I would ask:

  1. With all the new shortened syntax, is it really the way we should do it?
  2. When should I use the shortened way of writing records? (I would always want to validate that required fields have values and do it in the constructor).

Solution

  • In C# 11.0 preview it is possible to use required in the property declaration.

    public record Person
    {
        public required string FirstName { get; init; }
    
        public string? MiddleName { get; init; }
    }
    

    A good explanation article about it can be found here.