Type type = typeof(Program);
type = type.BaseType; // [CS8600] Converting null literal or possible null value to non-nullable type.
do
{
type = type.BaseType; // [CS8602] Dereference of a possibly null reference. + [CS8600] Converting null literal or possible null value to non-nullable type.
}
while(true);
在上面的程序中,我希望编译器发出相同的警告(
BaseType
可以为空,因此不能将其分配给type
变量)。而实际上在第二种情况下,我得到了另一个对我来说似乎错误的错误(type
变量根据定义不能为空)。
这是编译器中的某种错误吗?或者相反,编译器“非常聪明”,并且发现我确实尝试将 null 分配给不可为 null 的变量,因为这只是一个警告,所以现在它会显示两个警告?
在这种情况下,编译器确实“特别聪明”。
对于循环中的行
type = type.BaseType;
,它看到您正在将BaseType
(可能为空)分配给不应该为空的变量type
。这将产生 CS8600,其原因与 CS8600 的第一个实例相同。
它也看到
type
中的表达式type.BaseType
可能为空。这是因为编译器可以看到您刚刚为 type
分配了一个可能为空的东西。因此, type.BaseType
取消引用可能为空的事物,并且可能会抛出 NullReferenceException
。这会导致 CS8602。
在整个方法中跟踪每个变量的“空状态”。有关编译器如何进行空跟踪的更多信息,请参阅此处的文档。这里我在程序的每一行注释了
type
的空状态:
Type type = typeof(Program);
// not null, because typeof(Program) never produces null
type = type.BaseType;
// maybe null, because BaseType is of type 'Type?'
do
{
// still maybe null here
type = type.BaseType;
// still maybe null here
}
while(true);
// not null, because this line is unreachable :)