可空引用类型:"Try" 方法模式,返回 false 时收到 null 警告

Nullable reference types: "Try" method pattern, getting warning for null when returning false

我有以下使用“尝试”模式的方法。

public bool TryGetValue(string subnet, [NotNullWhen(true)] out TValue value)
{
    if (!TryFindNode(subnet, out var node))
        throw new InvalidOperationException();
    if (TValueIsDefault(node.Value) == false)
    {
        value = node.Value;
        return true;
    }
    value = default;
    return false;
}

在线 value = default - 我收到编译器警告 CS8601:“可能的空引用赋值”。下一行 returns falsevalue 具有 [NotNullWhen(true)] 属性。

我是不是遗漏了什么,或者编译器是否出于某种原因没有携带 value 的状态?

完整示例 sharplab.io and a Github gist

您可以看看类似的方法,例如 Dictionary<TKey, TValue>.TryGetValue, are implemented in .NET Core. In your case you should use null-forgiving operator ! 是如何抑制警告的(因为 TValue 声明为不可空类型)

value = default!;
return false;

(以下答案适用于 Visual Studio 16.6/.NET Core 3.1)

在这种情况下,您应该使用 [MaybeNullWhen(false)] 而不是 [NotNullWhen(true)]

public bool TryGetValue(string subnet, [MaybeNullWhen(false)] out TValue value)
{
    if (!TryFindNode(subnet, out var node))
        throw new InvalidOperationException();
    if (TValueIsDefault(node.Value) == false)
    {
        value = node.Value;
        return true;
    }
    value = default;
    return false;
}

解释:

要理解的关键点是应用 [NotNullWhen(true)] 属性并不意味着 [MaybeNullWhen(false)].

在您的示例中,允许提供不可为 null 的引用类型,例如 string 作为 TValue 的类型参数。这将产生以下方法:

public bool TryGetValue(string subnet, [NotNullWhen(true)] out string value)
{
    if (!TryFindNode(subnet, out var node))
        throw new InvalidOperationException();
    if (TValueIsDefault(node.Value) == false)
    {
        value = node.Value;
        return true;
    }
    value = default; // Wait, default(string) is null! We can't do this!
    return false;
}

您可能想要做的不是告诉调用者该方法将 return“为真时不为空”,而是告诉他们“在为假时可能 return 为空”。然后,包含类型 TreeNode<TValue> 类型参数 将告知调用者是否应该在该方法 return 为真时期望非空 value。因此实例化看起来像:

public bool TryGetValue(string subnet, [MaybeNullWhen(false)] out string value)
{
    if (!TryFindNode(subnet, out var node))
        throw new InvalidOperationException();
    if (TValueIsDefault(node.Value) == false)
    {
        value = node.Value;
        return true;
    }
    value = default; // ok
    return false;
}

因为赋值的目标有MaybeNullWhen,编译器允许你给它赋值null。我们只需在您的 return 语句中检查变量的空状态是否与 return 值兼容。例如,如果我们将上面的 return false 更改为 return true,您将收到可空性警告。