Search code examples
c#outc#-8.0nullable-reference-types

The "out" keyword of C# 8 doesn't pass "System.Diagnostics.CodeAnalysis" rules?


I'm converting some code from C#5 to C#8, enabling nullable-check in compilation ruleset,

<Nullable>enable</Nullable>

then I met a problem like this:

class Person
{
    public int MI { get; set; } = 3;
}
class UseWeakReference
{
    public static void Main(string [] args)
    {
        Person person = new Person();
        WeakReference<Person> wr = new WeakReference<Person>(person);

        wr.TryGetTarget(out Person p1); // doesn't compile
        Console.WriteLine(p1);
    }
}

The compilation error is:

CS8600: Converting null literal or possible null value to non-nullable type.

What's the real cause of this compiling error, and how to fix it?


Solution

  • You can allow the out parameter to be a possible null reference and compare it with null value after method call

    wr.TryGetTarget(out Person? p1);
    if (p1 != null)
        Console.WriteLine(p1);
    

    Or simply check the return result of TryGetTarget method: when it's true, the p1 can't be null

    var result = wr.TryGetTarget(out Person? p1);
    if (result)
        Console.WriteLine(p1);
    

    The reason of compiler warning is that TryGetTarget implemented like that

    public bool TryGetTarget([MaybeNullWhen(false), NotNullWhen(true)] out T target)
    {
        // Call the worker method that has more performant but less user friendly signature.
        T o = this.Target;
        target = o!;
        return o != null;
    }
    

    The nullability of out parameter determined based on return value, according to [MaybeNullWhen(false), NotNullWhen(true)] attributes, and can't be determined at compile time, only at runtime.

    When you assign it to non-nullable reference, compiler warns you about possible problems. Checking the return result or use Person? seems to be a proper solution here