沒有一個應該編譯。 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