それらのどれもコンパイルするべきではありません。C#仕様では、スイッチセクションに少なくとも1つのステートメントが必要です。パーサーはそれを禁止する必要があります。
パーサーが空のステートメントリストを許可するという事実を無視しましょう。それは関係のあることではありません。仕様では、スイッチセクションの端に到達可能なエンドポイントがあってはならないことが規定されています。それが関連するビットです。
最後の例では、スイッチセクションに到達可能なエンドポイントがあります。
void M(int x) { switch(2) { case 2: ; } }
したがって、エラーである必要があります。
あなたが持っていた場合:
void M(int x) { switch(x) { case 2: ; } }
その場合、コンパイラはxが2になるかどうかを知りません。控えめに言って、xが2になる可能性があると想定し、switch caseラベルが到達可能であるため、セクションに到達可能なエンドポイントがあると言います。
あなたが持っていた場合
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
ため、エンドポイントは到達可能と見なされます。