Eine switch-Anweisung vergleicht einen Wert mit einer Liste konstanter case-Labels und führt den passenden Abschnitt aus. In C# muss jeder Abschnitt mit break enden (oder mit einer anderen Anweisung, die ihn verlässt), ein Fall kann also nie stillschweigend in den nächsten laufen.
Ausgabe:
200: OK
302: redirect
404: not found
500: unhandled status
Der Wert in Klammern wird einmal ausgewertet und mit jedem Label verglichen. default läuft, wenn nichts passt; es ist optional und darf überall in der Liste stehen, steht aber meist am Ende. Gibt es keinen Treffer und kein default, tut der ganze switch nichts.
Jeder Abschnitt braucht ein break
In C, C++, Java und JavaScript läuft die Ausführung bei vergessenem break in den nächsten Fall. C# macht aus diesem Fehler einen Kompilierfehler:
switch (level)
{
case 1:
Console.WriteLine("read");
// error CS0163: Control cannot fall through from one case label ('case 1:') to another
case 2:
Console.WriteLine("write");
break;
}
Die Regel lautet: Das Ende der Anweisungsliste eines Abschnitts darf nicht erreichbar sein. break ist der übliche Weg, das zu erfüllen, aber alles, was den Abschnitt verlässt, funktioniert:
returnverlässt die ganze Methode, oft die sauberste Form in einer kleinen Hilfsmethode.throwlöst eine Exception für einen Wert aus, der nie vorkommen sollte.continuespringt zum nächsten Durchlauf, wenn derswitchin einer Schleife steht.goto caseundgoto defaultspringen absichtlich in einen anderen Abschnitt.
Der letzte Abschnitt ist nicht ausgenommen. Ein default: am Ende ohne break scheitert mit CS8070, Control cannot fall out of switch from final case label ('default:').
Mehrere Werte in einem case
Labels ohne Anweisungen dazwischen teilen sich den Abschnitt darunter. Das ist die einzige Art des Durchfallens, die C# erlaubt, weil ein leeres Label keinen Code verstecken kann:
Ausgabe:
'O' is a vowel
'k' is a consonant or symbol
' ' is a space
'7' is a digit
Jeder Abschnitt endet hier mit return, also ist kein break nötig (ein break nach einem return wäre unerreichbarer Code). Zwei Labels mit demselben Wert sind ein Fehler, CS0152 The switch statement contains multiple cases with the label value '1', und jedes Label muss eine Konstante zur Kompilierzeit sein: Eine Variable in einem case scheitert mit „a constant value is expected“.
switch auf einen String
Nach Ganzzahlen sind Strings der häufigste switch-Wert. Der Vergleich ist ordinal und beachtet Groß- und Kleinschreibung, normalisiere die Eingabe also vor dem switch:
Ausgabe:
Starting the server
Stopping the server
Server is running
Unknown command: restart
Unknown command: (none)
Ohne ToLowerInvariant würde "STOP" bei default landen. Ein null-Wert ist als switch-Wert erlaubt: Er passt auf keine String-Konstante und fällt zu default, der switch selbst wirft also nie.
switch auf ein Enum
Genau dafür wurde switch gemacht: eine geschlossene Menge benannter Werte.
Ausgabe:
Pending: wait for payment
Paid: pack and ship
Shipped: track the parcel
Delivered: nothing, order is closed
Cancelled: nothing, order is closed
ArgumentOutOfRangeException for value 42
Der Compiler prüft nicht, ob eine switch-Anweisung jedes Enum-Member abdeckt, und eine Enum-Variable kann jede Ganzzahl ihres zugrunde liegenden Typs enthalten ((OrderStatus)42 ist erlaubt). Das default, das wirft, macht aus einem vergessenen Fall einen sofortigen, offensichtlichen Fehler statt einer stillen Nichtaktion.
goto case und goto default
Wenn ein Fall wirklich in einen anderen übergehen soll, lässt C# dich den Sprung ausschreiben:
Ausgabe:
admin:
manage users
edit posts
read posts
editor:
edit posts
read posts
guest:
read posts
goto case nimmt eine Konstante, die auf eines der Labels im selben switch passen muss. In echtem Code ist es selten: Gemeinsames Verhalten ist meist als Methode klarer, die mehrere Fälle aufrufen. Trotzdem ist es die Antwort auf „wie falle ich in C# durch“.
Variablen in Fällen
Der ganze switch-Block ist ein einziger Gültigkeitsbereich, zwei Fälle können also keine Variable mit demselben Namen deklarieren:
switch (shape)
{
case "square":
int area = side * side;
break;
case "rectangle":
int area = width * height; // error CS0128: A local variable or function named 'area' is already defined in this scope
break;
}
Setze den Rumpf jedes Abschnitts in geschweifte Klammern, um ihm einen eigenen Gültigkeitsbereich zu geben: case "square": { int area = side * side; ... break; }.
break in einer Schleife
break in einem case verlässt den switch, nicht die Schleife drumherum. continue tut das Gegenteil: Ein switch ist keine Schleife, also springt continue zum nächsten Durchlauf der Schleife.
Ausgabe:
end marker found
Total: 134
Die Schleife lief nach "end" weiter und addierte 99. Um die Schleife aus einem switch heraus zu beenden, setze ein Flag und prüfe es nach dem switch, oder verschiebe die Schleife in eine Methode und nutze return. Die Seite zu break und continue vergleicht die Optionen.
case-Labels mit Mustern und when
Seit C# 7.0 kann ein case-Label statt einer Konstante ein Muster sein: Es kann den Typ des Werts prüfen und eine when-Bedingung ergänzen. Diese Form ist in modernem C#-Code verbreitet:
static string Describe(object value)
{
switch (value)
{
case null:
return "nothing";
case int n when n < 0:
return $"negative int {n}";
case int n:
return $"int {n}";
case string s when s.Length == 0:
return "empty string";
case string s:
return $"string \"{s}\"";
default:
return $"other: {value.GetType().Name}";
}
}
Bei Mustern zählt die Reihenfolge: Der erste passende Fall gewinnt, und der Compiler meldet einen Fehler, wenn ein Fall nie erreicht werden kann, weil ein früherer ihn schon abdeckt (case int n: über case int n when n < 0: zu setzen scheitert). Die when-Klausel funktioniert auch bei konstanten Fällen: case 0 when isAdmin:. C# 9 hat relationale und logische Muster hinzugefügt, ein case kann also case >= 90: oder case 'a' or 'e' or 'i': lauten.
In C# 7 ohne Muster ist dieselbe Unterscheidung nach Typ eine if-Kette mit dem is-Typmuster:
Ausgabe:
negative int -3
int 12
empty string
string "hi"
other: Decimal
nothing
Wenn jeder Zweig eines switch nur einen Wert berechnet, ist der switch-Ausdruck noch kürzer: var grade = score switch { >= 90 => "A", >= 80 => "B", _ => "C" };. Die Seite zum switch-Ausdruck behandelt seine Syntax, Muster und die Regeln zur Vollständigkeit.
Worauf du switchen kannst
| Werttyp | Konstante Fälle | Hinweise |
|---|---|---|
int, long, byte und andere Ganzzahlen | ja | der klassische Fall |
char | ja | case 'a': |
string | ja | ordinal, beachtet Schreibweise, null geht zu default |
bool | ja | erlaubt, aber ein if ist klarer |
jedes enum | ja | keine Prüfung auf Vollständigkeit |
double, decimal | ab C# 7 | nur Konstanten; Bereiche brauchen relationale Muster aus C# 9 |
| jeder andere Typ | ab C# 7 | über Typmuster, case Circle c: |
Häufig gestellte Fragen
Ist break in einem C#-switch Pflicht?
Jeder case-Abschnitt muss mit einer Anweisung enden, die ihn verlässt: meist break, aber auch return, throw, continue (in einer Schleife) oder goto case zählen. Vom Ende eines Abschnitts in den nächsten zu fallen ist ein Kompilierfehler, CS0163 Control cannot fall through from one case label ('case 1:') to another, und das gilt auch für den letzten Abschnitt.
Wie behandle ich in C# mehrere Werte in einem switch-case?
Stapele die Labels ohne etwas dazwischen: case "sat": case "sun": Console.WriteLine("weekend"); break;. Leere case-Labels dürfen zum nächsten Label durchfallen; nur ein Abschnitt mit Anweisungen muss mit break enden. Ab C# 9 kann ein Muster-case auch case 1 or 2 or 3: lauten.
Beachtet ein C#-switch auf einen String Groß- und Kleinschreibung?
Ja. String-Fälle werden ordinal und mit Beachtung der Schreibweise verglichen, "Yes" passt also nicht auf case "yes":. Normalisiere den Wert vorher mit switch (input.Trim().ToLowerInvariant()). Ein null-String passt auf keinen konstanten Fall und landet bei default.
Kann ein C#-switch durchfallen wie in C oder Java?
Nicht implizit. Wenn ein Fall in einen anderen übergehen soll, sag es mit goto case <value>; oder goto default;. So ist jedes Durchfallen im Code sichtbar, und deshalb verbietet C# die stille Variante.
Was ist der Unterschied zwischen einer switch-Anweisung und einem switch-Ausdruck in C#?
Eine switch-Anweisung führt Anweisungen aus und braucht case, break und default. Ein switch-Ausdruck (ab C# 8) erzeugt einen Wert: var label = n switch { 0 => "zero", > 0 => "positive", _ => "negative" };. Nimm den Ausdruck, wenn jeder Zweig nur ein Ergebnis berechnet.