Search code examples
c#.net-corenullreferenceexceptionnullablenullable-reference-types

How can I tag a value as not expected to be null?


I have a function that's correctly specified as returning a potentially-null object. My code calls that function but in a way where it isn't going to return a null.

MyClass? MyFunction(string x);
/* ... */
var myObject = MyFunction("Never return null.");
myObject.MyMemberFunctionOfMyClass();

Visual Studio (correctly) flags the use of myObject as a "possible null reference". I know that it will never be null but the compiler doesn't know that.

Is there a way to flag this as a known can't-be-null? I know I could add a test for null, but that would be duplicating the test-for-null/throw-NullReferenceException code that the compiler will insert anyway and my function is very neat and tidy without it. I'd also rather not use the #pragma that turns off the warning as I want to keep the warning for other values.

I'd prefer some way of wrapping up a single value in a cloak of "This value won't be null. Continue as you were."

var myObject = MyFunction("Never return null.").NotNull();

Does such a thing exist?


Solution

  • If you are really sure something is not null, and you don't want to pay a performance cost for a redundant null check, you can always use ! to suppress it.

    var myObject = MyFunction("Never return null.")!;
    

    Which you might choose to put in a wrapper function with an explanation.

    If the function really can sometimes return null, it may also be possible to annotate the condition that the return may or may not be null, for example.

        [return: NotNullIfNotNull(nameof(input))]
        public static string? Foo(string? input)
        {
            if (input == null) return null;
            else return input + "bar";
        }
        public static void Test()
        {
            string a = Foo(null); // Warning
            string b = Foo("hello"); // No warning
            string? c = Foo(null); // No warning
            string d = Foo(b); // No warning
            string e = Foo(c); // Warning
    }
    

    However the possibilities for these are fairly limited.

    Another option without just suppressing with a ! would be to make a version of the function that does not return null, and throws (or maybe asserts if really want to avoid release performance costs) if given inputs might result in null. In the simplest case this might be a wrapper. Giving more protection than just silencing the warning.

    public static string? MaybeNull(string input) // 3rd party thing you can't change
    {
        if (input.Length < 5) return null;
        else return input;
    }
    public static string NeverNull(string input)
    {
        if (input.Length < 5) throw new ArgumentException("Must be at least 5 characters.", nameof(input));
        string? ret = MaybeNull(input);
        Debug.Assert(ret != null);
        return ret!;
    }
    public static string NeverNull2(string input)
    {
        string? ret = MaybeNull(input);
        if (ret == null) throw new ArgumentException("Invalid input.", nameof(input));
        return ret;
    }