Updated on

Compiler warning CS8618 tells us that a non-nullable member can still be null when the constructor finishes. The compiler prints it in a form that depends on what we declared. For a property and a field, the two forms are:

Non-nullable property 'FirstName' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Non-nullable field 'LastName' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Both forms say the same thing: we promised this member is never null, and nothing in the type guarantees it. In this article, we look at why the warning appears and at six ways to resolve it, including the required modifier that the message now recommends first.

To download the source code for this article, you can visit our GitHub repository.

What Causes the CS8618 Warning?

Let’s consider a simple class:

public class Address
{
    public string FirstName { get; set; }
}

If we instantiate the Address class, by default FirstName will be null. The following code would then throw a System.NullReferenceException:

var address = new Address();
int length = address.FirstName.Length;

CS8618 comes from nullable reference types, a C# 8 feature that lets us declare which references are allowed to be null and then checks that we keep our word.

Inside a nullable context, string FirstName { get; set; } is a promise that the property is never null. The compiler traces every constructor. If any of them can finish with the member still unassigned, the promise is broken and it warns.

An auto-property with no initializer and no constructor assignment breaks it immediately: its backing field starts at default, and default for a reference type is null.

The warning comes from static analysis, so nothing fails at run time yet. CS8618 marks where a future NullReferenceException will come from while it is still cheap to fix.

We turn the analysis on with <Nullable>enable</Nullable> in the project file. Project templates have set it for new projects since .NET 6, which is why the warning shows up in projects whose authors never opted in.

The nullable reference types feature aims to minimize the chances of our code throwing a NullReferenceException by analyzing the null-state of variables and warning when we may accidentally dereference a null.

How Do We Fix the CS8618 Warning?

Six fixes resolve CS8618, and what separates them is who takes responsibility for the value.

Give the member a value the type controls: a property initializer, or an assignment in every constructor. The type guarantees non-null and nothing downstream has to think about it.

Declare it string? if null is a valid value. The warning then moves to the code that uses the member: every dereference of a possibly null value needs a null check first, and the compiler warns wherever one is missing.

Mark it required and the caller must supply it in an object initializer. This is what the message recommends first, and the compiler enforces it.

Annotate a shared initialization method with [MemberNotNull] when several constructors set the member through one helper.

The last two, = null! and #pragma warning disable, only switch the check off. The member is still null and the NullReferenceException still arrives, just later and without a warning.

  • Initialize non-nullable properties
  • Change the type to be nullable
  • Disable the warning
  • Use the null forgiving operator
  • Use the required keyword
  • Annotate a helper method with [MemberNotNull]

We should choose the option based on the specific context of our code.

Initialize All Non-nullable Properties

If we set sensible default values for our properties when the class is instantiated then this is a good way of avoiding dereferencing a null later in our code and therefore protects us from throwing a NullReferenceException:

public class Address
{
    public string FirstName { get; set; } = "Bob";
}

Alternatively, we can set the value of FirstName through the constructor of the Address class:

public Address()
{
    FirstName = "Bob";
}

Our article on the best way to assign an initial value to auto-properties compares the two in more detail.

However, we may not be able to assign a suitable default value for all properties when we instantiate the Address class. If this is the case, we should consider other ways of addressing the warning.

Change the Type to Be Nullable

If it is valid for the property to be null, we can make this explicit and change the type of the property to be nullable. For our example, we can change the type of our property from string to string?:

public class Address
{
    public string? FirstName { get; set; }
}

Now when we reference FirstName elsewhere in our code, we can see that the type is nullable and therefore we will know to check for a null value.

Disable the Warning

We can stop the compiler from emitting these warnings by using preprocessor directives. In fact, we can disable any warning if we know the corresponding code:

public class Address
{
#pragma warning disable CS8618
    public string FirstName { get; set; }
#pragma warning restore CS8618
}

Alternatively, rather than disabling the specific warning, we can disable the nullable warning context for a specific section of code:

public class Address
{
#nullable disable
    public string FirstName { get; set; }
#nullable restore
}

If we want to disable nullable analysis at the project level, we can add or set <Nullable>disable</Nullable> in our .csproj project file instead.

#pragma warning disable CS8618 does not cover CS9264, so a property rewritten to use the field keyword can start warning again.

Use the Null Forgiving Operator

The null-forgiving operator ! suppresses all nullable warnings for the preceding expression:

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

In our example, we suppress a nullable warning, yet FirstName is still null and our code will still throw exceptions if we try and dereference FirstName later in our code. We look at what the null! statement does in a separate article.

Use the required Keyword

From C# 11, we can use the required keyword to create the required members:

public class Address
{
    public required string FirstName { get; set; }
}

required does not suppress the warning, it discharges it. The compiler stops warning us because the obligation has moved to whoever constructs the object, and it now enforces that obligation as an error rather than a warning: leaving FirstName out of the object initializer fails the build with CS9035.

We cover required members and how the compiler enforces them in a separate article.

Initialize in a Helper Method With MemberNotNull

When several constructors share one initialization method, the compiler cannot see that the method assigns the member, so it warns in every constructor. MemberNotNullAttribute tells it what the method guarantees:

using System.Diagnostics.CodeAnalysis;

public class Address
{
    public string City { get; set; }

    public Address() => SetCity();

    public Address(string city) => SetCity(city);

    [MemberNotNull(nameof(City))]
    private void SetCity(string? city = default) => City = city ?? "Default City";
}

The attribute is a promise we make on the method’s behalf, and the compiler checks it: it stops warning about City in both constructors and warns inside SetCity() instead, with CS8774, if the method can finish without assigning City.

Which CS8618 Fix Should We Use?

One question decides it: after this fix, is the member never null, or have we only stopped the compiler asking?

If the type can supply a sensible value, the initializer or a constructor assignment is the right answer and the cheapest one to read.

If the member has no sensible value until the caller provides one, required is the fix the compiler itself recommends, and it turns a warning we can ignore into an error we cannot.

If null is a legitimate state, string? says so, and the null checks it forces on the code that reads it are the cost of that design.

That leaves = null! and #pragma warning disable. Both claim that we know better than the analysis. They are right for frameworks that assign members through reflection, an EF Core DbSet being the standard example, and wrong almost everywhere else.

Here are all seven options side by side:

FixCodeWho guarantees non-nullWarning after the fix
Property initializerpublic string City { get; set; } = "Default City";The type, alwaysNone
Constructor assignmentpublic Address(string city) => City = city;The type, at constructionNone
Nullable typepublic string? Country { get; set; }Nobody; callers must null-checkNone here, CS8602 at each possibly null dereference
required modifierpublic required string Area { get; set; }The caller, enforced at compile timeNone; omitting it is error CS9035
Null-forgiving operatorpublic string PostalCode { get; set; } = null!;Nobody; the check is switched offNone, and NullReferenceException at run time if we were wrong
[MemberNotNull] helper[MemberNotNull(nameof(City))] private void SetCity(string? city = default)The type, through the annotated methodNone
#pragma warning disable CS8618around the declaration, or around the constructor if the class declares oneNobody; the message is suppressedNone, and NullReferenceException at run time if we were wrong

For the required row, the caller sets the member in an object initializer, such as new Address { Area = "Test Area" }.

Why Does the field Keyword Report CS9264 Instead?

C# 14 added the field contextual keyword, which gives an accessor body access to the compiler-generated backing field without our declaring one. A property written that way gets a different diagnostic code.

CS9264 is the field-keyword version of CS8618, and its message ends with three suggestions instead of two. The compiler says: “Consider adding the ‘required’ modifier, or declaring the property as nullable, or safely handling the case where ‘field’ is null in the ‘get’ accessor.”

#pragma warning disable CS8618 does not suppress CS9264. Code that was quiet under the old suppression can start warning again the moment a property is rewritten to use field, because the diagnostic code in the pragma no longer matches the one the compiler reports.

The third suggestion is usually the best fix available, because it needs no initializer, no required modifier and no suppression. Returning a fallback from the get accessor means callers never see null.

Handling the null case inside the accessor resolves CS9264 without changing the property’s public type:

public class Address
{
    public string Town
    {
        get => field ?? string.Empty;
        set => field = value;
    }
}

field refers to the backing field the compiler generates for Town. Nothing else about the property changes, and callers still see a plain non-nullable string. Our article on properties vs fields in C# covers the field keyword itself.

Conclusion

We’ve seen that the “Non-nullable property must contain a non-null value” warning is part of the improved static flow analysis that warns when we may try and dereference null. It is worth us understanding why the compiler is warning us and considering the options we have to address it. The safest option is to ensure we initialize all non-nullable properties with default non-null values. If that’s not possible or appropriate, we could change the type to nullable. Finally, if we are sure that we do not dereference a null elsewhere in our code, we could use the null forgiving operator or disable the warning entirely.

Tested with .NET 10.0.10 (SDK 10.0.302) and C# 14.