通过VS.NET 2010评估C#常量表达式

5
当我在Visual Studio中尝试了一个C#示例表达式时。
public int Test()
{
    if (10/2 == 5)
        throw new Exception();
    return 0;
}

当我写下表达式10/2 == 5时,VS.NET会自动抛出一个“检测到无法访问的代码”的警告。
如果我将表达式改为10/2 == 6,那么IDE就会很开心?这是怎么发生的?
编辑:抱歉问题没有讲清楚。它发生得如此迅速,甚至在编译代码之前就发生了?
我已经按照FIFO原则点赞了每个回复并接受了第一个答案。

2
没有人回答真正的问题:为什么编译器在第二种情况下不抱怨异常是无法到达的? - Adam
@codesparkle,我在我的回答中已经提到了这一点。 - Jeppe Stig Nielsen
7个回答

9
if (10/2 == 5)

将始终返回 true,这意味着

throw new Exception();

始终会被执行,且

return 0;

永远不会被执行


4
如果你反编译这段代码,你将得到以下结果:
public int Test()
{
     throw new Exception();
}

我认为由于这些是常量值,所以数学计算是在编译时完成的,因此10/2实际上不是10/2,而是5...所以编译器很容易意识到5==5总是成立。事实上,我相信这些常量将自动转换为true。编译器的目标是优化掉总是重复并在编译时运行其处理的代码,而不是一遍又一遍地运行同样的处理。
因此,基本上编译器意识到由于if始终为true并且if通过return(通过throw)导致了返回,所以它会优化掉它知道永远不会被执行的代码。因此,反编译的代码结果就是以上内容。
事实上,如果你输入10/2 == 6,则相反的情况会发生,“常数化”为5 == 6,然后变成false。由于if永远为false,它将被优化掉:
public int Test()
{
    int num = 0;
    return num;
}

4

就像其他人所说的那样,编译器可以在编译时评估表达式10 / 2 == 5,因为它是一个常量表达式。它评估为true,因此在if范围之后的任何代码都是无法到达的。如果这个表达式改为false,则if内部的代码将无法到达。

现在考虑这段代码:

public int TestA() 
{ 
    if (10 / 2 == 5) 
        return 1; 
    return 0; 
} 

public int TestB() 
{ 
    if (10 / 2 == 6) 
        return 1; 
    return 0; 
} 

两种方法都会生成关于无法到达代码的警告!

C#编译器的奇怪之处在于,如果无法到达的代码完全由throw语句组成,则不会发出有关无法访问性的警告。

附加:这个Stack Overflow问题相关


3
它在抱怨这一行。
return 0;

永远无法到达。10/2始终等于5。


2
在第一种情况下,编译器处理表达式10/2 == 5,该表达式的结果为true,因此会抛出异常,并且return 0语句是无法到达的。
在第二种情况下,10/2 == 6的结果为false,因此return 0语句是可到达的,因为没有抛出异常。
针对您的编辑:您的代码实际上不必编译,编译器就可以知道该行代码是无法到达的。它足够聪明,知道10/2 == 5始终为真,而不考虑任何用户输入,这意味着异常将总是被抛出。

1
编译器足够智能(这是一个非常简单的检查),并确定 return 0 永远不会被执行。这是因为 10/2 == 5 总是成立的。根据编译器,以下表达式的计算结果相同。
if (10/2 == 5)

或者

if true

编译器能够确定这一点的原因是因为这些数字不是“变量”。

1

实际上,他知道他永远不会回来

他只是警告说,在10/2 == 5下面的整个代码将永远不会被解释,因为10/2始终为5。

同样地:

if (true)
{
     ......
}
else 
{
  .....
}

1
那么现在编译器是男的了吗?;P - contactmatt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接