这是一个启用了可空引用类型的示例C#程序:
请注意,
然而,如果通过通用方法返回未初始化的结构体(例如使用上面的
更糟糕的是,一些代码分析工具会错误地警告不要检查
这似乎是C#中可空性分析的一个重大“漏洞”,我必须想知道是否有什么方法可以让编译器理解这种情况。有没有办法“告诉”编译器
using System;
using System.Collections.Generic;
using System.Linq;
MyStruct myStruct = new("A");
List<MyStruct> list = new() { myStruct };
MyStruct found = list.FirstOrDefault(item => item.Str == "B");
Console.WriteLine(found.Str.Length);
struct MyStruct
{
public readonly string Str;
public MyStruct(string str)
{
Str = str;
}
}
请注意,
MyStruct
包含一个非空的 Str
字段。从理论上讲,这意味着 Str
字段永远不应该为空,并且编译器在几乎所有情况下都会警告您是否将其留空。然而,如果通过通用方法返回未初始化的结构体(例如使用上面的
FirstOrDefault
调用),则可以滑入 null 值。在这种情况下,Str
字段将为空,但 C# 编译器不会发出任何警告,无论是在访问 Str
还是在分配 found
变量时,因此当程序尝试访问 found.Str.Length
时,程序会崩溃并显示 NullReferenceException
。(另一个情况是从数组中读取结构体。)更糟糕的是,一些代码分析工具会错误地警告不要检查
found.Str
是否为空。(例如,如果我添加if(found.Str != null)
,Resharper将报告为“表达式始终为真”,并提示删除它,即使在这种情况下它绝对不是真的。)这似乎是C#中可空性分析的一个重大“漏洞”,我必须想知道是否有什么方法可以让编译器理解这种情况。有没有办法“告诉”编译器
found
结构体的字段可能为空,即使它们被声明为不可为空?
编辑:澄清一下,我知道this article和this question的答案,它们解释了为什么会发生这种情况。但我感兴趣的是该怎么办。具体来说,有没有办法告诉编译器某个实例字段可能为空,即使它被标记为非空,而不必更改该字段的实际声明以使其可为空。就像你可以在表达式后面添加!
来告诉编译器,“相信我,这不是null,尽管它被标记为可为空”,我想做的是相反的,即“相信我,尽管它被标记为非空,但它可能为null”。(如果有一种方法可以自动处理结构体实例的所有字段,那就更好了,但我对此表示怀疑。)
Nullable
已启用。 - Walt D