Visual Studio null引用警告 - 为什么没有错误?

时间:2009-09-11 20:52:25

标签: c# visual-studio compiler-construction nullreferenceexception

我注意到Visual Studio特有的一些东西。首先,尝试在函数中的某处键入此(C#):

class Foo  
{  
    public void Bar()  
    {  
        string s;
        int i = s.Length;
    }
}

现在,它会立即将s中的s.Length标记为错误,并说“Use of unassigned local variable 's'”。另一方面,请尝试以下代码:

class Foo  
{  
    private string s;
    public void Bar()  
    {  
        int i = s.Length;
    }
}

它会进行编译,并在s的{​​{1}}下方加上警告,并提示“private string s”。

现在,如果VS很聪明并且知道s将始终为null,为什么在第二个示例中获取其长度不是错误?我最初的猜测是,“如果编译器根本无法完成其工作,它只会产生编译错误。由于代码在技术上运行只要你从不调用Bar(),它只是一个警告。”除非第一个例子使解释无效。只要你从不调用Bar(),你仍然可以毫无错误地运行代码。什么给出了什么?只是疏忽,还是我错过了什么?

4 个答案:

答案 0 :(得分:8)

第一个示例(错误)是编译器definite-assignment跟踪的示例,仅适用于局部变量。由于上下文有限,编译器对这种情况有一个密不透风的掌握。请注意,s不为空,未定义。

在第二个示例中,s是一个字段(默认为null)。没有编译器错误,但它将始终在运行时捕获。这种特殊情况可能会被困住,但编译器通常无法检测到这种错误 例如,您可以添加一个方法Bar2(),该方法会将字符串分配给s,但会在Bar()之后调用,或者根本不调用。{{1}}。这将消除警告,但不会消除运行时错误。

所以它是设计的。

答案 1 :(得分:3)

对于第二个示例,代码有效,它可能无法正常运行。以下是该程序可以“成功”执行的几种情况

  • 编译器不是100%正确。如果通过反射修改实例,则“s”可能具有非空值。
  • 如果没有调用方法Bar
  • ,程序可以无错误地执行
  • 此程序可能是一个测试程序,它会因测试原因触发NullReferenceException

答案 2 :(得分:0)

我唯一猜到的是,在第二个例子中,s可以通过反射来改变(使用BindingFlags.Private来访问私有成员)。

答案 3 :(得分:0)

在第一个示例中, s 是一个局部变量,编译器可以在使用之前轻松检查 s varible是否已分配。

在第二个中, s 是一个全局变量,它可能是在类的其他地方初始化的。