编译时间错误和无法访问的代码

InB*_*een 8 c#

好的,请考虑以下代码:

private const int THRESHHOLD = 2;

static void Main(string[] args)
{
     string hello;

     if (THRESHHOLD > 1) return;
     Console.WriteLine(hello);        
}
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,这段代码没有抛出" 使用未分配的局部变量'hello' "编译时错误.它只是发出警告" 检测到无法访问的代码 ".

即使代码无法访问,它仍然是编译时错误,我认为正确的做法是抛出编译时错误.如果我要做以下事情:

private const int THRESHHOLD = 2;

static void Main(string[] args)
{
     string hello;

     if (THRESHHOLD > 1) return;
     hello.LMFAO();       
}
Run Code Online (Sandbox Code Playgroud)

果然,我得到一个" '字符串'不包含'LMFAO'的定义,并且没有扩展方法'LMFAO'接受类型'string'的第一个参数可以找到(你是否缺少using指令或汇编引用? ) "编译时错误.

为什么使用未分配的变量不一样?

编辑改变了const变量,使其不那么分散注意力.我想许多人都忽略了问题的重点,这取决于哪种情况,编译时错误优先于无法访问的代码.

Jam*_*are 12

如果您查看第5节中的C#语言规范,它会声明:

对于要在某个位置明确赋值的初始未分配变量,必须在通向该位置的每个可能执行路径中进行对变量的赋值.

并在5.3.3.1中进一步说明:

v绝对是在任何无法访问的语句的开头分配的.

由于不可到达的代码不是可能的执行路径,因此不必为了避免错误而分配它.

至于你的问题为什么未知函数是无法访问的代码中的编译器错误而未分配的变量不是.你必须考虑上面的标准.无法访问的代码并不意味着它无法在语法上有效.代码仍然必须是可编译的,唯一的区别是无法访问的代码使得它考虑在该点分配的所有最初未分配的变量.但这并不意味着您可以像未定义的变量或方法那样注入语法无效的东西.

未分配变量的错误消息也给了我们一个提示,它告诉我们在使用之前必须分配一个最初未分配的变量,但由于代码无法访问,因此技术上并未使用...


Eri*_*ert 12

James Michael Hare的回答给出了法律上的解释:本地变量明确分配的,因为代码是不可达的,并且所有局部变量都是在无法访问的代码中明确分配的.换句话说:如果有办法观察未初始化的局部变量的状态,程序只是一个错误.在你的程序中没有办法观察本地,因此它不是一个错误.

现在,我注意到编译器不需要无限聪明.例如:

void M()
{
    int x = 0;
    int y;
    if (x + 0 == x) return;
    Console.WriteLine(y);
}
Run Code Online (Sandbox Code Playgroud)

你知道并且我知道该方法的最后一行是无法访问的,但编译器不知道这一点,因为可达性分析器不知道零是整数的加性同一性.编译器认为最后一行可能是可访问的,因此会出错.

有关在编程语言中设计可达性和明确赋值分析器的更多信息,请参阅我关于此主题的文章:

http://blogs.msdn.com/b/ericlippert/archive/tags/reachability/

http://blogs.msdn.com/b/ericlippert/archive/tags/definite+assignment/

我注意到,虽然没有人回答更深层次的问题,这就是为什么错误会在无法访问的代码中被抑制?如您所知,我们在无法访问的代码中提供其他语义分析错误.

要考虑该决定的优缺点,您必须考虑为什么有人会首先获得无法访问的代码.无论是故意无法访问还是无意无法访问.

如果无意中无法访问,则程序包含错误.该警告已经引起了对主要问题的注意:代码无法访问.如果存在无法访问的代码,则该方法的控制流程存在严重错误.很可能开发人员必须对方法的控制流程进行严格的改变; 我们对无法访问的代码进行的任何局部变量分析可能会产生误导性噪音.让开发人员修复代码以便一切都可以访问,然后我们将分析现在可访问的与控制流相关的错误代码.

如果无法访问无法访问的代码,因为开发人员打算无法访问它,那么很可能他们正在执行以下操作:

// If we can Blah, then Frob. However, if we cannot Blah and we can Baz, then Foo.
void M()
{
    int y;
    // TODO: The Blah method has a bug and always throws right now; fix it later.
    if (false /* Blah(out y) */ )
    {
        Frob(y);
    }
    else if (Baz(out y))
    {
        Foo(y);
    }
}
Run Code Online (Sandbox Code Playgroud)

该程序应该Frob(y)错误的吗?