启用C# 8 Nullable特性后,为何编译器提示局部变量可能为空?
C# 8可空特性常见疑惑解答
一、编译器提示errorsList可能为空的原因
C# 8的可空静态分析无法自动识别Dictionary.TryGetValue的内部逻辑——当方法返回true时,out参数会被赋值为非空集合实例。默认情况下,TryGetValue的out参数被标记为可空类型,编译器不会根据方法返回值推断参数的非空状态,因此会提示errorsList可能为空。
要彻底解决这个问题,需要给TryGetValue方法添加[NotNullWhen(true)]特性,明确告诉编译器:当方法返回true时,对应的out参数不为空。
二、为何errorsList.Count没有空引用警告?
这是编译器静态分析的盲区导致的:
- 一方面,
Count是值类型属性,编译器默认认为访问值类型属性不会直接触发空引用异常(但实际运行时如果errorsList为空,还是会抛出NullReferenceException); - 另一方面,在
if (TryGetValue(...))代码块内,编译器会做隐式的非空假设,但这种假设并不严谨,也没被可空分析规则正式认可,所以出现了“提示errorsList可能为空,却不警告Count访问”的矛盾情况。
三、添加null-forgiving operator !仍提示为空的原因
你把!用错了位置——!是作用于可空变量,而非方法调用表达式。当前你把!加在TryGetValue方法调用后面,只是断言方法返回值不为空,并没有标记errorsList为非空。
正确用法是直接在errorsList上使用!,有两种方式:
- 在
out参数声明时标记:
if (dict.TryGetValue(key, out var errorsList!))
- 在访问
errorsList成员时标记:
errorsList!.Count
另外,如果没有给TryGetValue添加[NotNullWhen(true)]特性,即使加了!,编译器可能仍会保留警告,建议优先通过特性标注完善类型推断,而非依赖!强制压制警告。
内容的提问来源于stack exchange,提问作者user16276760
相关产品推荐
相关产品推荐

