Special Offer: My C#/.NET Bootcamp Course is out now. Get 10% OFF using the code FRIENDS10.

The required keyword fixes object initializers and can potentially change how you implement classes in C#. Stick with me to the end and decide if it will change how you use C#.


When working with Nullable Reference Types (NRTs), you have seen it over and over again. You have a few non-nullable properties, and the compiler issues a warning because the properties must contain a value when exiting the constructor.

In this video, I will show you how the new required keyword fixes this issue and why I believe it to be the best new compiler feature in C# 11.

Introduction

C# 11 was released in November 2022 and can be used in projects targeting .NET 7. Let’s find out how the required keyword works and when you can use it.

Let’s look at the following Book class containing two string properties for the Title and the Author.

public class Book
{
    // CS8618: Non-nullable property 'Title' must contain non-null value when exiting constructor. Consider declaring the property as nullable.
    public string Title { get; set; }
    // CS8618: Non-nullable property 'Author' must contain non-null value when exiting constructor. Consider declaring the property as nullable.
    public string Author { get; set; }
}

Object construction

Currently, the compiler issues a warning because we declare a property of a non-nullable reference type and do not provide a value in the constructor. We can create a new object of type Book resulting in an instance of a Book without a value in the Title or the Author properties.

var book1 = new Book(); // No value provided for the Title and the Author properties.

We could use the object initializer syntax and provide an author and a title for the Book, resulting in an instance with values in both properties. However, the compiler still allows us to create objects using the default constructor. Therefore the warnings in the class remain.

var book2 = new Book
{
    Author = "Agatha Christie",
    Title = "The Moving Finger",
};

Implementing a constructor

The traditional solution prior to C# 11 was to implement a constructor that populates all the non-nullable reference type properties.

Let’s add a constructor with two parameters that populate the properties’ values.

public class Book
{
    public Book(string author, string title)
    {
        Author = author;
        Title = title;
    }

    public required string Title { get; set; }
    public required string Author { get; set; }
}

As you can see, the warning is gone. However, we now have two compiler errors when creating the Book objects. First, we use the constructor without providing arguments. 

var book1 = new Book(); // Compiler error because there is no constructor accepting 0 arguments.

It makes sense because, in the class, we defined that we want to have values for all non-nullable properties when the object is created. We can fix the compiler error by providing the arguments it requires.

var book1 = new Book("Agatha Christie", "The Moving Finger");

With two arguments, that’s perfectly fine. However, depending on the properties, you could be mixing up the first and the second argument. 

For example, imagine a Person object where we have to provide a first and a last name. Imagine reading code where an object with “Peter” and “Riley” is created. Is it Peter Riley, or Riley Peter?

To avoid these mix-ups, the object initializer syntax allows us to state the property name before assigning the value. Yes, we could also use named arguments for the constructor, but who does this?

However, with the current implementation, we force the users of the class to use the constructor with two parameters, and we cannot use the object initializer syntax anymore.

var book2 = new Book // Compiler error: No constructor is accepting 0 arguments.
{
    Author = "Agatha Christie",
    Title = "The Moving Finger",
};

The Required Keyword

Well, finally, the stage is set for the required keyword to help us resolve the issue. Let’s add the required keyword to both the Title and the author properties.

public class Book
{
    public Book(string author, string title)
    {
        Author = author;
        Title = title;
    }

    public required string Title { get; set; }
    public required string Author { get; set; }
}

What changes? Well, at first sight, we see compiler errors when using the constructor and when using the object initializer syntax. Let’s take a closer look at it.

First, let’s comment the constructor to make things simpler. The Book class now only contains two properties with the required keyword applied.

One important thing to realize is that we now do not provide values for the non-nullable reference type properties required in the Book class. The compiler errors appear where the object is created and not where the class is implemented. 

We can also say that the required keyword puts the blame on the caller instead of the implementer of the class.

The compiler error for the object initializer syntax is gone. We now call the parameterless default constructor and provide values for all required properties.

var book1 = new Book("Agatha Christie", "The Moving Finger");
// CS9035: Required member 'Book.Title' must be set in the object initializer or attribute constructor.
// CS9035: Required member 'Book.Author' must be set in the object initializer or attribute constructor.

var book2 = new Book // CS7036: There is no argument given that corresponds to the required parameter 'author' of 'Book.Book(string,string)'
{
    Author = "Agatha Christie",
    Title = "The Moving Finger",
};

public class Book
{
    public Book(string author, string title)
    {
        Author = author;
        Title = title;
    }

    public required string Title { get; set; }
    public required string Author { get; set; }
}

But how do we create Book objects using the constructor? Let’s add the constructor definition again. As you can see, we still have the compiler error stating that “The required members must be set in the object initializer or attribute constructor”.

We already used the object initializer syntax, but what is the “attribute constructor” part meaning?

Well, there currently is a limitation that the compiler does not check if we provide values for all required properties in a constructor.

It means that the developer has the responsibility of populating all required properties. We can tell the compiler that we populate all required properties using the SetsRequiredMembers attribute.

The description of the attribute says, “Specifies that this constructor sets all required members for the current type, and callers do not need to set any required members themselves”.

var book1 = new Book("Agatha Christie", "The Moving Finger"); // compiles fine

var book2 = new Book // still a compiler error
{
    Author = "Agatha Christie",
    Title = "The Moving Finger",
};

public class Book
{
    [SetsRequiredMembers]
    public Book(string author, string title)
    {
        Author = author;
        Title = title;
    }

    public required string Title { get; set; }
    public required string Author { get; set; }
}

With the SetsRequiredMembers attribute applied, we can now use the constructor to create objects of the Book type. However, how can we use the object initializer syntax?

We add a parameterless constructor.

var book1 = new Book("Agatha Christie", "The Moving Finger");

var book2 = new Book
{
    Author = "Agatha Christie",
    Title = "The Moving Finger",
};

public class Book
{
    public Book()
    {
    }

    [SetsRequiredMembers]
    public Book(string author, string title)
    {
        Author = author;
        Title = title;
    }

    public required string Title { get; set; }
    public required string Author { get; set; }
}

We can now use the parameterless constructor and provide values using the object initializer syntax, or we can use the constructor that guarantees that all required properties are populated.

Let’s see what happens if we remove the title from the constructor. We get a compiler error because we do not provide an argument to the second parameter of the constructor. Let’s revert the change and do the same for the object initializer syntax.

As you can see, if we do not provide a value for a required property, we also get a compiler error when using the object initializer syntax. This is all due to using the required keyword on the property. 

Let’s remove the required keyword on the Title property. As you can see, the compiler error on the object initializer syntax disappears. Let’s add it back on before we mess up our code.

Conclusion

In conclusion, the required keyword in C# fixes a few problems, especially when working with Nullable Reference Types (NRTs).

We can choose if we want to be able to use the constructor or the object initializer syntax or both. If we only need the object initializer syntax, we do not need to implement any constructor.

If we want to implement a constructor, we need to make use of the SetsRequiredMembers attribute to tell the compiler that we populate values for all required members when executing the constructor.

When trying it out yourself, make sure you use C# 11, .NET 7, and if you use Visual Studio 2022, use version 17.4 or higher.

Let me know on Twitter if this will also be a game changer for you or how you currently create data objects. 

Continue to read about all the important changes in .NET 7 or the 15 new features in Visual Studio 2022 v17.5.

Subscribe to my YouTube channel if you want to learn more about .NET development in the future.

 

Claudio Bernasconi

I'm an enthusiastic Software Engineer with a passion for teaching .NET development on YouTube, writing articles about my journey on my blog, and making people smile.