Search code examples
c#.netnullable

New c# nullable option


In new version of C# is default option nullable. I mean this

Visual Studio project settings where nullable reference types can be enabled and disabled

It's really good feature for me. But I don't understand one thing. Is property nullable by me or by program?

I know that this property should never be null because I fill it in the form and never set it as null. But in general it can be null. How should I mark it?

Example:

UserModel:

public string? Name { get; set; }

public string Name { get; set; } = null!

I'm really confused.


Solution

  • I know that this property should never be null because I fill it in the form and never set it as null. But in general it can be null. How should I mark it?

    If it is set to non-null in the constructor, then you can declare it a string rather than string? because it really is guaranteed to never be null.

    If, however, it is null after the constructor has run (and before any other methods are called) then it CAN be null and you should declare it as string?.

    The dichotomy you face is that (from what you say) it should never be null when the class is used correctly - i.e. if the calling code does indeed call the method that initialises the property to non-null before accessing it, it will be guaranteed to be not null - which means you would like to declare it as a non-null string so that callers don't need to use the null-forgiving ! operator to suppress nullable warnings.

    What to do in this case? Well I think you have three possibilities:

    1. Declare the property as nullable: string? and let the callers suppress the nullable warning or check the value for null.
    2. Initialise the property to a non-null default such as string.Empty and declare the property as non nullable string.
    3. Assume that accessing the property when it is null is a programming error, and throw an appropriate exception.

    For the last case, you could do something like this:

    private string? _name;
    
    public string Name 
    { 
        get
        {
            if (_name == null)
                throw new InvalidOperationException("Do not access Name without setting it to non-null or calling Init()");
                
            return _name;
        }   
        
        set
        {
            if (value == null)
                throw new ArgumentNullException("value", "You cannot set Name to null.");
                
            _name = value;
        }
    }
    

    This assumes that there's a method called Init() that can be called to initialise Name, but of course your code may vary.

    Regardless of which of those approaches you take, you should really check for null in the property setter, as shown above.

    Note that a more succinct way of writing the setter null check is:

    set
    {
        _name = value ?? throw new ArgumentNullException("value", "You cannot set Name to null.");
    }