代码之家  ›  专栏  ›  技术社区  ›  Tesserex

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

  •  5
  • Tesserex  · 技术社区  · 15 年前

    我注意到了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 在里面 private string s 带着警告说 Field 'Foo.s' is never assigned to, and will always have its default value null “。

    现在,如果vs很聪明并且知道s总是空的,为什么在第二个例子中获取其长度不是一个错误呢?我最初的猜测是,“如果编译器不能完成它的工作,它只会给出一个编译错误。因为从技术上讲,只要你不调用bar()代码就可以运行,所以这只是一个警告,“除了第一个例子使解释无效。只要不调用bar(),就可以无错误地运行代码。那给了什么?只是疏忽,还是我遗漏了什么?

    4 回复  |  直到 15 年前
        1
  •  8
  •   Henk Holterman    15 年前

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

    在第二个示例中, S 是一个字段(默认为空)。没有编译器错误,但它总是在运行时被捕获。这种特殊情况可能会被捕获,但这种错误一般不会被编译器检测到。
    例如,您可以添加一个方法 Bar2() 将字符串赋给 S 但要迟于 Bar() 或者根本没有。这将消除警告,但不会消除运行时错误。

    所以是设计出来的。

        2
  •  3
  •   JaredPar    15 年前

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

    • 编译器不是100%正确的。如果通过反射修改实例,“s”可能具有非空值。
    • 如果从未调用方法栏,则程序可以无错误地执行。
    • 此程序可能是一个测试程序,由于测试原因正在触发NullReferenceException
        3
  •  0
  •   Robert Fraser    15 年前

    我只能猜测,在第二个示例中,可以通过反射(使用bindingFlags.private访问私有成员)更改s。

        4
  •  0
  •   Vadim    15 年前

    在第一个样本中 S 是局部变量,编译器可以轻松检查 S 变量在使用前没有被分配。

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