C# 可为空性未正确推导

标签 c# c#-8.0 nullable-reference-types c#-9.0

考虑:

#nullable enable

class Manager { 
  public int Age; 
}

class Archive {
  readonly Dictionary<string, Manager> Dict = new Dictionary<string, Manager>();

  public (bool ok, Manager? value) this[string key] {
    get {
      return Dict.TryGetValue(key, out var value) ? (true, value) : (false, null);
    }
  }
}

然后我尝试:

Archive archive = new Archive();
var (ok, john) = archive["John"];
if (!ok) return;
int age = john.Age; // <-- warning

我收到警告:

Warning CS8602 Dereference of a possibly null reference.

为什么?我预计在检查 !ok 后,编译器将推断出 john 不为 null

我尝试的另一件事是:

public (bool ok, Manager value) this[string key] {
  get {
    return Dict.TryGetValue(key, out var value) ? (true, value) : default;
  }
}

(从管理器结果中删除了 ? 并将 (false, null) 替换为 default)
我现在没有收到警告,但如果删除 !ok 的检查,我也不会收到警告。

有什么方法可以实现我想要的 - 警告当且仅当之前没有检查!ok(也就是说我忘记检查它)

谢谢

最佳答案

Why ? I expected that after checking for !ok the compiler will deduce that john is not null

这不起作用的原因有两个:

  1. 可空性分析一次仅查看一种方法。

分析时:

Archive archive = new Archive();
var (ok, john) = archive["John"];
if (!ok) return;
int age = john.Age; // <-- warning

编译器看不到这个方法:

  public (bool ok, Manager? value) this[string key] {
    get {
      return Dict.TryGetValue(key, out var value) ? (true, value) : (false, null);
    }
  }

ok 为 true 时,告诉 value 不为 null。

  • 可为空性分析不跟踪 bool 变量。
  • 目前,编译器还不够智能,无法跟踪 bool 变量的来源,并根据它们更新可空性。例如,以下内容不会发出警告:

    M(string? str)
    {
        if (string != null)
            Console.WriteLine(str.Length);
    }
    

    但是下面的等效代码可以:

    M(string? str)
    {
        var isNotNull = string != null;
        if (isNotNull)
            Console.WriteLine(str.Length);
    }
    

    Is there any way to achieve what I want here - a warning if and only if there was no previous check for !ok (that is I forgot to check for it)

    恐怕不是元组。最好的方法是使用 out 参数,尽管这意味着您无法使用索引器:

    public bool TryGetManager(string key, [NotNullWhen(true)] Manager? manager) 
        => Dict.TryGetValue(key, out manager);
    

    关于C# 可为空性未正确推导,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63845429/

    相关文章:

    c# - 在显示之前找到 ContextMenuStrip 的高度

    c# - "Nullable context"实际上做了什么?

    c# - 避免对具有可为空类型/字段的泛型发出警告的最佳方法?

    c# - asp.net mvc 模型绑定(bind)不绑定(bind)集合

    c# - 更新特定的 ListView 项值

    C#:为什么范围的上限是互斥的?

    c# - 在 C# 8.0 中,有没有办法公开类的默认成员实现?

    c# - 如何将 "any non-nullable type"指定为泛型类型参数约束?

    json - 如何使用 System.Text.Json 处理可为 null 的引用类型?

    c# - 如何编码 C# 结构数组?