【问题标题】:Visual Studio null reference warning - why no error?Visual Studio 空引用警告 - 为什么没有错误?
【发布时间】:2009-09-11 20:52:25
【问题描述】:

我注意到 Visual Studio 的一些特殊之处。首先,尝试在函数的某处输入这个(C#):

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

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

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

它将编译,并在private string s 中的s 下划线并带有警告,说“Field 'Foo.s' is never assigned to, and will always have its default value null”。

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

【问题讨论】:

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


    【解决方案1】:

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

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

    这是设计使然。

    【讨论】:

      【解决方案2】:

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

      • 编译器并非 100% 正确。如果通过反射修改实例,则“s”可能具有非空值。
      • 如果从未调用方法 Bar,则程序可以正常执行
      • 此程序可能是一个测试程序,由于测试原因触发了 NullReferenceException

      【讨论】:

        【解决方案3】:

        我能做出的唯一猜测是,在第二个示例中,可以通过反射更改 s(使用 BindingFlags.Private 访问私有成员)。

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

          • s 不是全局的,它是一个实例字段。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-23
          • 1970-01-01
          • 2021-04-01
          • 2011-02-11
          • 1970-01-01
          相关资源
          最近更新 更多