在启用了可为空的引用类型的C#8项目中,我有以下代码,我认为应该向我发出有关可能的null取消引用的警告,但不会:
public class ExampleClassMember
{
public int Value { get; }
}
public struct ExampleStruct
{
public ExampleClassMember Member { get; }
}
public class Program
{
public static void Main(string[] args)
{
var instance = new ExampleStruct();
Console.WriteLine(instance.Member.Value); // expected warning here about possible null dereference
}
}
[使用默认构造函数初始化instance
时,instance.Member
设置为ExampleClassMember
的默认值,即null
。因此,instance.Member.Value
将在运行时抛出NullReferenceException
。据我了解C#8的可空性检测,我应该收到关于这种可能性的编译器警告,但我没有。为什么呢?
请注意,对Console.WriteLine()
的呼叫没有理由发出警告。引用类型属性不是可为null的类型,因此编译器无需警告它可能为null。
[您可能会争辩说,编译器应警告struct
本身中的引用。在我看来,这是合理的。但是,事实并非如此。这似乎是一个漏洞,是由值类型的默认初始化引起的,即,必须始终有一个默认(无参数)构造函数,该构造函数总是始终将所有字段清零(对于引用类型字段为空,对于数字类型为零,等等)。 )。
我称它为漏洞,因为从理论上讲,不可为空的参考值实际上应该始终为非!咄。 :)
此博客文章中似乎解决了此漏洞:Introducing Nullable Reference Types in C#
避免为空到目前为止,警告是关于防止可空引用中的空值被取消引用。硬币的另一面是要避免在不可为空的引用中完全没有为空。
有多种方法可以产生空值,并且其中大多数值得警告,而其中一些将引起另一“警告之海”,最好避免:…
- 使用具有非空引用类型字段的结构的默认构造函数。这是一个偷偷摸摸的工作,因为默认构造函数(将结构归零)甚至可以在很多地方隐式使用。 可能最好不要发出警告 [强调我的],否则许多现有的结构类型将变得无用。
换句话说,这是一个漏洞,但不是漏洞。语言设计者已经意识到了这一点,但是选择将这种情况保留在警告范围之外,因为鉴于struct
初始化的工作方式,否则这样做是不切实际的。