71

I have a question regarding nullable reference type system available since C# 8.

Suppose we have a C# domain model class with a mutable reference type property like below:

public class Person
{

    public string Name { get; set; }

    public Person(string name)
    {         
        Name = name;
    }
}

So far no problem. But consider real world scenario, I often want to check the validity of the property as it's a public mutable property and I have to make sure the model invariant whenever property is changed.

public class Person
{
    private string _name;
    public string Name
    {
        get => _name;
        set => _name =
            value ?? throw new ArgumentNullException("Name is required.");
    }
    public Person(string name)
    {         
        Name = name;
    }
}

Then compiler generates CS8618 warning, basically saying:

Non nullable field _name is not initialized. Consider declare the field as nullable type.

So every time I encounter the warning I have to enclose the constructor with the following pragma directive.

#pragma warning disable CS8618
public Person(string name)
{         
    Name = name;
}
#pragma warning restore CS8618

But I think it's redundant and tedious to do it always. Am I misusing something or is there better way to write such property without warning?

Of course I can change the property type to string? as compiler suggests but notionally it's not acceptable as a solution as Person should always have non null name and we want to explicit about such invariant condition in domain class.

Another solution I considered is to drop the argument validation logic and just relying on the nullable compiler warning, but it's not always possible (I mean often validation other than null check is also required.), it's just warning anyway in regular project settings, so I don't think it's a good solution.

2
  • 2
    Not that it helps any for an immediate fix. C# 9.0's Init only properties seem to be the perfect fit. Again, not an answer, but something to look forward to! Commented Sep 4, 2020 at 13:07
  • Know it's old but instead of string? or null! you could use required modifier like public required string Name {get;set;} to suppress that warning. Commented Nov 18, 2024 at 15:15

7 Answers 7

80

For now you can avoid this warning by initializing a _name field using default value with null-forgiving operator !, like

private string _name = default!;

or

private string _name = null!;

There is also an open GitHub issue for that.

You can also declare the _name as string? and specify that return value of Name property can't be null (even if string? type allows it), using NotNull attribute

private string? _name;

[NotNull]
public string? Name
{
    get => _name;
    set => _name = value ?? throw new ArgumentNullException("Name is required.");
}

It should be fine, otherwise compiler shows you a warning before validation logic will take place in a setter

set => _name = value ?? throw new ArgumentNullException("Name is required.");

Consider the following code

var person = new Person(null);

In this case you'll get

warning CS8625: Cannot convert null literal to non-nullable reference type.

before ArgumentNullException will be thrown.

If you set <TreatWarningsAsErrors>true</TreatWarningsAsErrors> or treat CS8625 warning as error, your exception won't be thrown

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, the null-forgiving operator using the default value is a clean solution IMO when you are certain that the value will be set in the flow, in another method
Thanks! Especially consider that the link in VS goes to a page that says: Sorry, we don't have specifics on this C# error
what about initializing a field or a property with string _name = ""; ? is there any difference? considering i don't care about it being null and treat null and empty the same.
Strangely enough the NotNullAttribute did not extinguish the CS8618 warning on an auto-property in a .NET 6 project with the current VS version. But the " = null!" did the trick and I feel is equally intuitive for other developers as the attribute. Only the AllowNullAttribute worked at the property level, I guess because it's documented as a pre-condition, that is it appears the CS8618 only respects "pre-conditional" null forgiving attributes? However I feel reading "allow null" is not intuitive. MemberNotNull(nameof(Property)) on the initialization method didn't work either.
48

You can disable the rule by creating an .editorconfig file (with the attached code) in the root of your project. It does not solve it but it will no longer show the warning

[*.cs]

# CS8618: Non nullable field _name is not initialized. Consider declare the field as nullable type
dotnet_diagnostic.CS8618.severity = none

2 Comments

How to create .editorconfig file learn.microsoft.com/en-us/visualstudio/ide/…
Is there an option to keep the warning alive, AND ignore it just for dotnet format? Since dotnet format version 9.0.0 (Nov 2024) the missing question mark will be add during "dotnet format". For me too much, a linter, should not change the "types" of my properties.
25

You can now apply MemberNotNull attribute on the setter to let the C# compiler know that non-nullability condition for the _name field is being maintained by that method.

C# language reference

using System.Diagnostics.CodeAnalysis;

public class Person
{
    private string _name;
    
    public string Name
    {
        get => _name;

        [MemberNotNull(nameof(_name))]
        set => _name = value ?? throw new ArgumentNullException("Name is required.");
    }

    public Person(string name)
    {         
        Name = name;
    }
}

1 Comment

wow... thank you very much! this is a better solution to my long-standing problem when I used a method in the constructor that initializes "not-null" members. Now I know that the initializing method should be marked with the MemberNotNull attribute. This attribute is also good because if I forget to initialize some "not-null" class member in the marked method, I will still get a warning.
5

Based on this:

Warnings for initialized fields Q: Why are warnings reported for fields that are initialized indirectly by the constructor, or outside the constructor?

A: The compiler recognizes fields assigned explicitly in the current constructor only, and warns for other fields declared as non-nullable. That ignores other ways fields may be initialized such as factory methods, helper methods, property setters, and object initializers. We will investigate recognizing common initialization patterns to avoid unnecessary warnings.

So with that being said, for now, moving the assignment directly into the constructor, is the only possible way. And for sure, using the pragma directive seems fine for this IMO.

Comments

4

To disable this warning and other null-related warnings for the whole Project, right click on your project -> Properties. Under the section Build -> General, set Nullable to Disable.

Tested on Visual Studio version 17

1 Comment

If I'm not mistaken, this will disable the language feature (so-called nullable reference types) instead of suppressing the warnings.
2

I'd like to further expand Pavel Anikhouski's answer by pointing out that using null-forgiving operator is considered a proper practice according to MS C# language reference.

You can also use the null-forgiving operator when you definitely know that an expression cannot be null but the compiler doesn't manage to recognize that.

4 Comments

This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review
Really? Proper practice? One explicitly declare something non-nullable, then force it to be null. That must certainly go against the non-nullable feature.
@ThomasEyde: You're not forcing it to be null. It's just used when the compiler throws a warning because it thinks a variable or property could be null in some situation, and you want to suppress that warning because you know (perhaps due to checks elsewhere in your code) that situation will never arise.
If @EmilKucharczyk is referring to the practice of public string Name { get; set; } = default!, then you are forcing a non nullable property to null.
0

What if you did the initial null check in your constructor and then assigned it to your field and not your property, and since it is mutable publicly you can leave the null check in your property before assigning it to your field, i.e.

public class Person
{
    private string _name;
    public string Name
    {
        get => _name;
        set => _name = value ?? throw new ArgumentNullException("Name is required.");
    }

    public Person(string name)
    {         
        _name = name ?? throw new ArgumentNullException("name is required.");
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.