Keine von ihnen sollte kompilieren. Die C# -Spezifikation erfordert, dass ein Switch-Abschnitt mindestens eine Anweisung aufweist. Der Parser sollte es ablehnen.
Lassen Sie uns die Tatsache ignorieren, dass der Parser eine leere Anweisungsliste erlaubt; das ist nicht relevant. Die Spezifikation besagt, dass das Ende des Switch-Abschnitts keinen erreichbaren Endpunkt haben darf; das ist das relevante bisschen.
In Ihrem letzten Beispiel hat der Schalterabschnitt einen erreichbaren Endpunkt:
void M(int x) { switch(2) { case 2: ; } }
so muss es ein Fehler sein.
Wenn Sie hat:
void M(int x) { switch(x) { case 2: ; } }
dann der Compiler nicht weiß, ob x je 2 wird Sie geht davon aus, dass es konservativ konnte, und sagt, dass der Abschnitt einen erreichbaren Endpunkt hat, da das Schaltergehäuse Label ist erreichbar.
Wenn Sie
hatte
void M(int x) { switch(1) { case 2: ; } }
Dann kann der Compiler Grund dafür, dass der Endpunkt nicht erreichbar ist, weil der Fall Etikett nicht erreichbar ist. Der Compiler weiß, dass die Konstante 1 ist nie gleich der konstanten 2.
Wenn Sie hatte:
void M(int x) { switch(x = 1) { case 2: ; } }
oder
void M(int x) { x = 1; switch(x) { case 2: ; } }
Dann wissen Sie, und ich weiß, dass der Endpunkt nicht erreichbar, aber der Compiler weiß das nicht. Die Regel in der Spezifikation besagt, dass die Erreichbarkeit nur durch Analyse konstanter Ausdrücke bestimmt wird. Jeder Ausdruck, der eine Variable enthält, auch wenn Sie ihren Wert auf andere Weise kennen, ist kein konstanter Ausdruck.
In der Vergangenheit hatte der C# -Compiler Fehler, wo dies nicht der Fall war. Man könnte sagen Dinge wie:
void M(int x) { switch(x * 0) { case 2: ; } }
und der Compiler würde vermuten, dass x * 0 hatte 0 sein, deshalb der Fall Etikett nicht erreichbar ist. Das war ein Fehler, den ich in C# 3.0 behoben habe. Die Spezifikation besagt, dass nur Konstanten für diese Analyse verwendet werden, und x
ist eine Variable, keine Konstante.
Jetzt, wenn das Programm legal ist, kann der Compiler fortgeschrittene Techniken wie diese verwenden, um zu beeinflussen, welcher Code generiert wird. Wenn Sie sagen, so etwas wie:
void M(int x) { if (x * 0 == 0) Y(); }
Dann kann der Compiler den Code generieren, als ob Sie
void M(int x) { Y(); }
geschrieben hatte, wenn er will.Aber es kann nicht die Tatsache verwenden, dass x * 0 == 0
wahr ist, um die Erreichbarkeit von Aussagen zu bestimmen.
Schließlich, wenn Sie
void M(int x) { if (false) switch(x) { case 2: ; } }
haben, dann wissen wir, dass der Schalter nicht erreichbar ist, also der Block keinen erreichbaren Endpunkt, so ist dies überraschenderweise legal. Aber angesichts der Diskussion über, Sie wissen jetzt, dass
void M(int x) { if (x * 0 != 0) switch(x) { case 2: ; } }
nicht x * 0 != 0
als false
nicht behandeln, so dass der Endpunkt erreichbar angesehen wird.
Es ist möglich, dass der Compiler die erste optimieren kann, aber die zweite wegen der Zuweisung nicht entfernen kann. –
Meine Vermutung ist, dass '1' ein zur Kompilierungszeit bekannter konstanter Ausdruck ist, der den Compiler den gesamten Schalter optimieren lässt, während 'i = 1' ein nicht konstanter Ausdruck ist (obwohl er dem Compiler auch bekannt ist, um einen bestimmten Wert zu erzeugen), so versucht der Compiler den Schalter zu halten. – dasblinkenlight
In einer idealen Welt sollte der Compiler beide akzeptieren oder ablehnen. Es sollte sicherlich keinen Code für sie generieren. Aber in dieser Welt denke ich, es ist nur ein weiteres Beispiel für "The Forrest Gump-Effekt:" Dumm ist so dumm tut ":) F: Warum Zeit verschwenden? Braincells sogar diskutieren? – paulsm4