2012-02-23 101 views
8

好吧,考虑下面的代码:编译时错误和无法访问的代码

private const int THRESHHOLD = 2; 

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

    if (THRESHHOLD > 1) return; 
    Console.WriteLine(hello);   
} 

令人惊奇的是这个代码不抛出一个“使用未分配的局部变量的‘你好’”编译时错误。它只是给出了一个警告“无法到达的代码检测”。

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

private const int THRESHHOLD = 2; 

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

    if (THRESHHOLD > 1) return; 
    hello.LMFAO();  
} 

果然,我得到一个“‘串’不包含‘LMFAO’,没有扩展方法‘LMFAO’接受一个类型的第一个参数的定义“字符串'可以找到(你是否缺少使用指令或程序集引用?)“编译时错误。

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

编辑更改const变量,因此它更少分散注意力。我认为很多人都忽略了这个问题的重点,这取决于哪种情况,编译时错误优先于不可访问的代码。

+6

只是想知道:你曾经想TRUE;以评估什么,但'真'? – 2012-02-23 16:07:31

+2

未使用的变量不会阻止您的代码工作或编译,这就是为什么它只是一条警告消息。试图使用未定义的方法会阻止你的代码运行,所以是一个错误。我不确定我是否理解这个问题。 – AaronS 2012-02-23 16:09:01

+0

@BrianRasmussen也许他是来自'真'关键字全部大写的语言? – Servy 2012-02-23 16:10:59

回答

12

詹姆斯·迈克尔·黑尔的回答给出了法律上解释:局部变量明确赋值,因为代码是不可达到的所有局部变量的可达代码明确赋值。换句话说:如果有一种方法,程序只有一个错误观察未初始化的局部变量的状态。在你的程序中没有办法观察本地,因此它不是一个错误。

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

void M() 
{ 
    int x = 0; 
    int y; 
    if (x + 0 == x) return; 
    Console.WriteLine(y); 
} 

你知道,我知道,该方法的最后一行是不可达的,但是编译器不知道,因为可达性分析不知道,零是整数的添加剂身份。编译器认为最后一行可能是可访问的,因此会给出错误。

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

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

应该Frob(y)错误这个项目?

+1

好东西一如既往。感谢Eric的回答,以及你为什么实施的行为是理想的例子使得它更清晰。 – InBetween 2012-02-23 19:46:34

1

当编译器发现代码不可访问时,它不会为它生成代码 - 因此不存在问题。

如果您将return行取出,则最后一行变为可再次访问,编译器将为其生成代码,并且会告诉您存在问题。

12

如果您在C# language specification在第5的样子,它指出:

对于最初未分配的变量中绝对算得 在某个位置分配,必须 发生在每一个赋值给变量可能的执行路径通往该位置。

并进一步在5.3.3.1:

v在任何无法访问的语句开头明确赋值。

由于不可达的代码不是可能的执行路径,因此不需要指定它来避免错误。

至于你的问题,为什么一个未知函数是不可达代码中的编译器错误,而未赋值的变量不是。你必须考虑上面的标准。无法访问的代码并不意味着它不能在语法上有效。代码仍然必须是可编译的,唯一的区别是无法访问的代码会使它认为所有初始未分配的变量都在此时分配。但这并不意味着你可以注入一些像未定义的变量或方法那样的语法无效的东西。

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

+0

是的,行为是根据规范。我更感兴趣的是为什么可达性优先于明确的分配。埃里克的例子显示了一个你希望它如此的情况。感谢你的回答。 – InBetween 2012-02-23 19:50:02

+0

@InBetween:不用担心,他是上师:-) – 2012-02-23 19:52:41