C# 8 的 "out" 关键字没有通过 "System.Diagnostics.CodeAnalysis" 规则?

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

我正在将一些代码从 C#5 转换为 C#8,在编译规则集中启用可空检查,

<Nullable>enable</Nullable>

然后我遇到了这样的问题:

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);
    }
}

编译错误为:

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

这个编译错误的真正原因是什么,如何解决?

您可以允许 out 参数成为可能的空引用,并在方法调用后将其与 null 值进行比较

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

或者直接查看TryGetTarget方法的return结果:当是true时,p1不能是null

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

编译器警告的原因是TryGetTarget这样实现的

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;
}

out 参数的可空性根据return 值,根据[MaybeNullWhen(false), NotNullWhen(true)] 属性确定,不能在编译时确定,只能在运行时确定。

当您将其分配给不可为空的引用时,编译器会警告您可能出现的问题。检查 return 结果或使用 Person? 似乎是一个合适的解决方案

无法保证 p1 在方法 returns 时不会为 null。但是,TryGetValue 注释说如果它 returns true 那么输出参数将不会是 null,所以将您的代码编写为:

if(wr.TryGetTarget(out var p1))
{
    Console.WriteLine(p1);
}

p1 将具有类型 Person? 但编译器将进行流分析以表明 TryGetTarget 返回 true 它知道 p1 不是null 并且可以视为 Person