没有一个应该编译。 C#规范要求开关部分至少有一条语句。解析器应该禁止它。
让我们忽略解析器允许空语句列表的事实;这不是什么相关的。该规范指出,切换部分的结尾不得有可到达的终点;这是相关的一点。
在你的最后一个例子,开关部分具有到达终点:
void M(int x) { switch(2) { case 2: ; } }
所以它必须是一个错误。
如果您有:
void M(int x) { switch(x) { case 2: ; } }
那么编译器不知道如果x将永远是2.假设保守,它可以,并说,该部具有到达终点,因为开关的情况下标签是可达的。
如果你有
void M(int x) { switch(1) { case 2: ; } }
那么编译器可以推论端点不可达因为案件标签不可达。编译器知道该常数1是从不等于常数2
如果您有:
void M(int x) { switch(x = 1) { case 2: ; } }
或
void M(int x) { x = 1; switch(x) { case 2: ; } }
然后,你知道,我知道终点不在可达,但编译器不知道。规范中的规则是可达性只能通过分析常量表达式来确定。任何包含变量的表达式,即使通过其他方式知道它的值,也不是一个常量表达式。
在过去的C#编译器有错误的地方,情况并非如此。你可以说这样的话:
void M(int x) { switch(x * 0) { case 2: ; } }
,编译器会有理由相信X * 0必须是0,因此,本案的标签是不可达。那是我在C#3.0中修复的一个错误。该规范说只有常数用于该分析,而x
是一个变量,而不是一个常数。
现在,如果程序是合法那么编译器可以使用像这样的高级技术来影响生成的代码。如果你这样说:
void M(int x) { if (x * 0 == 0) Y(); }
那么编译器生成代码,就像你写
void M(int x) { Y(); }
如果它想。但是它不能使用x * 0 == 0
为确定语句可达性的事实。
最后,如果你有
void M(int x) { if (false) switch(x) { case 2: ; } }
那么我们知道,开关不可达,因此该块不具有到达终点,所以这是令人惊讶的,合法的。但考虑到上面的讨论,现在你知道
void M(int x) { if (x * 0 != 0) switch(x) { case 2: ; } }
不把x * 0 != 0
为false
,所以终点认为可以达到的。
编译器可能会优化第一个,但由于赋值而无法删除第二个。 – 2013-03-07 20:34:51
我的猜测是'1'是编译时已知的一个常量表达式,让编译器优化整个开关,而'i = 1'是一个非常量表达式(尽管编译器也知道产生一个特定的值),所以编译器试图保持开关。 – dasblinkenlight 2013-03-07 20:35:39
在理想的世界中,编译器可能应该接受或拒绝这两者。它当然不应该为它们生成任何代码。但在这个世界上,我认为这只是“阿甘正传效应的另一个例子:”愚蠢是愚蠢的“:) Q:为什么浪费时间/ braincells甚至讨论它? – paulsm4 2013-03-07 20:37:40