C# 编译时错误和无法访问的代码 OK,考虑下面的代码: private const int THRESHHOLD = 2; static void Main(string[] args) { string hello; if (THRESHHOLD > 1) return; Console.WriteLine(hello); }

C# 编译时错误和无法访问的代码 OK,考虑下面的代码: private const int THRESHHOLD = 2; static void Main(string[] args) { string hello; if (THRESHHOLD > 1) return; Console.WriteLine(hello); },c#,C#,令人惊讶的是,这段代码没有抛出“使用未分配的局部变量‘hello’”编译时错误。它只是给出一个警告“检测到无法访问的代码” 即使代码无法访问,它仍然是一个编译时错误,我认为正确的做法是抛出一个编译时错误。如果我要做以下事情: private const int THRESHHOLD = 2; static void Main(string[] args) { string hello; if (THRESHHOLD > 1) return; hello.L

令人惊讶的是,这段代码没有抛出“使用未分配的局部变量‘hello’”编译时错误。它只是给出一个警告“检测到无法访问的代码”

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

private const int THRESHHOLD = 2;

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

     if (THRESHHOLD > 1) return;
     hello.LMFAO();       
}
果然,我得到一个“'string'不包含'LMFAO'的定义,并且找不到接受第一个'string'类型参数的扩展方法'LMFAO'(是否缺少using指令或程序集引用?)”编译时错误

为什么使用未赋值变量不一样


EDIT更改了
const
变量,从而减少了干扰。我认为很多人都忽略了问题的要点,即什么取决于哪种情况,编译时错误优先于无法访问的代码。

当编译器看到代码无法访问时,它将不会为其生成代码,因此,没有问题

如果您将
return
行取出,那么最后一行再次变得可访问,编译器将为其生成代码,并会告诉您该行有问题。

如果您查看第5节中的,它会说明:

对于一个最初未分配的变量,要明确考虑 如果在某个位置赋值,则必须为变量赋值 在指向该位置的每个可能执行路径中发生

并在5.3.3.1中进一步说明:

v肯定是在任何不可到达语句的开头赋值的

由于不可到达的代码不是可能的执行路径,因此无需为其分配以避免错误

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


未分配变量的错误消息也给了我们一个提示,它告诉我们在使用之前必须分配最初未分配的变量,但因为代码无法访问,所以从技术上讲,它没有被使用…

詹姆斯·迈克尔·黑尔的回答给出了法律上的解释:局部变量是绝对分配的,因为代码是不可访问的,所有局部变量都在不可访问代码中指定。换句话说:如果有办法观察未初始化的局部变量的状态,则程序只是一个错误。在你的程序中,没有办法观察到局部,因此它不是一个错误

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

void M()
{
    int x = 0;
    int y;
    if (x + 0 == x) return;
    Console.WriteLine(y);
}
你知道,我也知道方法的最后一行是不可访问的,但是编译器不知道,因为可达性分析器不知道零是整数的加法标识。编译器认为最后一行可能是可访问的,因此给出了一个错误

有关在编程语言中设计可达性和确定分配分析器的更多信息,请参阅我的文章:

但我注意到,没有人回答更深层的问题,这就是为什么应该在无法访问的代码中抑制错误?正如您所注意到的,我们在无法访问的代码中给出了其他语义分析错误

考虑到这一决定的利弊,你必须首先思考为什么有人会有不可及的代码。它要么是有意不可及的,要么是无意不可及的

如果无意中无法访问,则程序包含错误。警告已经引起了人们对主要问题的注意:代码无法访问。如果存在无法访问的代码,则该方法的控制流存在严重错误。开发人员很可能不得不对方法的控制流进行重大更改;我们对无法访问的代码进行的任何局部变量分析都可能是误导性噪声。让开发人员修复代码,使所有内容都可以访问,然后我们将对现在可以访问的代码进行分析,找出与控制流相关的错误

如果不可访问的代码是不可访问的,因为开发人员希望它是不可访问的,那么很可能他们正在这样做:

// 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);
    }
}

Frob(y)
应该是这个程序中的一个错误吗?

只是想知道:您是否希望
TRUE
计算为除
TRUE
以外的任何值?一个未使用的变量不会阻止您的代码工作或编译,这就是为什么它只是一条警告消息的原因。尝试使用未定义的方法会阻止代码运行,这也是一个错误。我不确定我是否理解这个问题。@BrianRasmussen也许他来自一种语言,“true”关键字在所有大写字母中?有趣的另一个相关问题:因为未知方法(或变量)在语法上无效,在这种情况下,不可访问代码的唯一变化是它考虑了所有未分配的变量,因为它们必须在使用之前分配,并且不能在不可访问代码中使用。一如既往的好东西。谢谢你的回答,Eric,你的例子说明了为什么实现的行为是可取的。是的,行为符合规范。我更感兴趣的是为什么可达性优先于确定的赋值。Eric的示例显示了一个您希望如此的情况。谢谢你的回答。@中间:不用担心,他是上师:-)