代码之家  ›  专栏  ›  技术社区  ›  Ilya Chernomordik

C#编译器的可空性检查警告输出中可能存在错误

  •  0
  • Ilya Chernomordik  · 技术社区  · 2 年前
    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 可以为null,因此无法分配给 type 变量)。而实际上,在第二种情况下,我又犯了一个错误,在我看来是错误的( 类型 根据定义,变量不能为null)。

    这是编译器中的某种错误,还是相反,编译器“非常聪明”,发现我确实试图将null赋给不可为null的变量,而且由于这只是一个警告,它现在将显示这两个警告?

    如果我评论第一个作业,结果是一样的。

    1 回复  |  直到 2 年前
        1
  •  3
  •   Sweeper    2 年前

    在这种情况下,编译器确实“非常聪明”。

    对于线路 type = type.BaseType; 在循环中,它看到您正在分配 BaseType (可能为null)到变量 type 这不应该是空的。这将生成CS8600,原因与CS8600的第一个实例相同。

    看到表达式 类型 在里面 type.BaseType 可能为空。这是因为编译器可以看到你刚刚给它分配了一个可能为空的东西 类型 因此, 类型。基础类型 正在取消引用一个可能为空的东西,并可能抛出一个 NullReferenceException 。这会导致CS8602。

    在整个方法中跟踪每个变量的“空状态”。有关编译器如何进行空跟踪的更多信息,请参阅 the documentation here 在这里,我注释了null状态 类型 在程序的每一行:

    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 :)
    

    即使删除线条,结果也是一样的 type=类型。基础类型; 这是在循环之外,因为 这是一个循环 .即使 类型 在第一次迭代中不会为null,在第二次迭代中仍然可能为null。