break beendet eine Schleife vorzeitig. continue überspringt den Rest des aktuellen Durchlaufs und geht zum nächsten. Beide wirken auf die innerste umgebende Schleife und funktionieren in for, foreach, while und do while gleich.
Ausgabe:
process order of 45
skip invalid total 0
process order of 120
skip invalid total -5
process order of 80
test order found, stopping
after the loop
continue ist für 0 und -5 über die Verarbeitungszeile gesprungen. break hat die Schleife bei 999 gestoppt, 60 wurde also nie besucht, und die Ausführung ging bei der ersten Anweisung nach der Schleife weiter.
break: aufhören, wenn die Antwort feststeht
Der typische Einsatz von break ist eine Suche: Sobald du gefunden hast, was du gesucht hast, gibt es keinen Grund, den Rest anzusehen.
Ausgabe:
first invalid email at index 1
Der Iterator (i++) läuft nach einem break nicht, i enthielte also noch den passenden Index, wenn es außerhalb der Schleife deklariert wäre. Für einfache Suchen sagt ein Bibliotheksaufruf dasselbe: Array.FindIndex(emails, e => !e.Contains("@")) gibt den Index zurück (oder -1), und emails.Any(e => !e.Contains("@")) aus LINQ beantwortet, ob es einen ungültigen gibt.
continue: zum nächsten Durchlauf springen
continue ist eine Guard Clause für Schleifen. Statt die eigentliche Arbeit in ein if zu packen, weise die unerwünschten Fälle am Anfang ab:
Ausgabe:
pen costs 1.20
mug costs 8.00
Wohin continue als Nächstes springt, hängt von der Schleife ab. In einer for-Schleife führt es den Iterator aus und prüft dann die Bedingung. In einer while-Schleife springt es direkt zur Bedingung, was zu einem klassischen Bug führt:
int i = 0;
while (i < 10)
{
if (i % 2 == 0)
continue; // i++ below is skipped: i stays 0 forever
Console.WriteLine(i);
i++;
}
Aktualisiere den Zähler vor jedem continue, oder nimm eine for-Schleife, bei der die Aktualisierung im Kopf steht und immer läuft.
break in einem switch in einer Schleife
In einem switch beendet break den case-Abschnitt. Steht dieser switch in einer Schleife, gehört das break zum switch, nicht zur Schleife:
Ausgabe:
quit received
count = 2
Ein einfaches break im case "quit" hätte nur den switch beendet, die Schleife wäre weitergelaufen, und count wäre 3. Das goto springt zum Label nach der Schleife. Die Schleife in eine Methode zu verschieben und in diesem case return zu schreiben funktioniert ebenfalls und braucht kein Label.
Verschachtelte Schleifen verlassen
C# hat kein break mit Label wie break outer; in Java. Läuft eine Suche durch zwei verschachtelte Schleifen, beendet ein break in der inneren Schleife nur die innere; die äußere geht zur nächsten Zeile weiter. Es gibt drei Standardlösungen.
1. Ein Flag, das die äußere Schleife prüft:
Ausgabe:
first free seat: row 1, seat 2
2. goto zu einem Label hinter beiden Schleifen. Das ist die eine Stelle, an der viele C#-Styleguides goto akzeptieren, weil es genau „beide Schleifen verlassen“ ausdrückt:
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
if (seats[row, col] == 0)
{
Console.WriteLine($"first free seat: row {row}, seat {col}");
goto done;
}
}
}
done:
Console.WriteLine("search finished");
3. Eine Methode mit return, meist die sauberste Lösung, weil die Suche einen Namen bekommt und ihr Ergebnis zurückgeben kann:
Ausgabe:
first free seat: row 1, seat 2
C# 7.0 hat außerdem lokale Funktionen eingeführt, mit denen du diese Hilfsmethode in die aufrufende Methode setzen kannst. Das hier verwendete Muster mit out-Parameter wird auf der Seite zu ref und out erklärt.
goto und Labels
Ein Label ist ein Bezeichner mit folgendem Doppelpunkt, und goto label; springt dorthin. Die Regeln sind streng genug, um den schlimmsten Missbrauch zu verhindern:
- Das Label muss in derselben Methode stehen, im selben Block wie das
gotooder in einem umgebenden. Du kannst aus Blöcken herausspringen, aber nie in einen hinein: Von außen zu einem Label in einem Schleifenrumpf zu springen ist Fehler CS0159 (no such label within the scope of the goto statement). - Einen
finally-Block kannst du nicht mitgoto,breakodercontinueverlassen. - In einem
switchübergebengoto case 3;undgoto default;die Kontrolle an einen anderen Abschnitt. So drückt ein C#-switch Durchfallen aus, denn implizit in den nächsten Fall zu fallen ist ein Kompilierfehler.
Mit goto lassen sich auch Schleifen bauen (Rücksprung zu einem Label), aber eine while-Schleife sagt dasselbe in einer Form, die jeder Leser erkennt. Behalte goto zum Verlassen verschachtelter Schleifen und für switch-Abschnitte.
return, throw und Schleifen
return verlässt die ganze Methode und damit auch jede Schleife darin. throw tut dasselbe, indem es eine Exception auslöst. In einem try-Block mit finally führen break, continue, goto und return den finally-Block trotzdem aus, bevor die Kontrolle weitergeht. Deshalb ist es sicher, aus einer Schleife auszusteigen, die in einem using-Block eine Datei offen hält.
| Anweisung | Verlässt | Weiter bei |
|---|---|---|
continue | den aktuellen Durchlauf | dem nächsten Durchlauf (Iterator, dann Bedingung) |
break | die innerste Schleife oder den innersten switch | der Anweisung danach |
goto label | alle umgebenden Blöcke | dem Label |
return | die Methode | dem Aufrufer |
throw | alles bis zu einem passenden catch | dem catch-Block |
Häufig gestellte Fragen
Was ist der Unterschied zwischen break und continue in C#?
break beendet die innerste Schleife (oder den innersten switch) sofort; die Ausführung geht danach weiter. continue beendet nur den aktuellen Durchlauf und springt zum nächsten: In einer for-Schleife läuft als Nächstes der Iterator, in while und do while wird als Nächstes die Bedingung geprüft, in foreach wird das nächste Element geholt.
Wie verlasse ich in C# verschachtelte Schleifen?
C# hat kein break mit Label. Die drei Optionen: ein bool-Flag setzen und in der äußeren Schleife prüfen, mit goto zu einem Label hinter beiden Schleifen springen oder die Schleifen in eine Methode verschieben und mit return verlassen. Die Methodenvariante ist meist die sauberste, weil die Suche dadurch auch einen Namen und einen Rückgabewert bekommt.
Verlässt break in einem switch die Schleife in C#?
Nein. In einem switch, der in einer Schleife steht, beendet break den switch-Abschnitt, und die Schleife läuft weiter. Um die Schleife aus einem case heraus zu verlassen, nimm return, ein Flag, das nach dem switch geprüft wird, oder goto zu einem Label nach der Schleife. continue in einem case geht dagegen zum nächsten Durchlauf der Schleife.
Ist goto in C# erlaubt?
Ja. goto label; springt zu label: in derselben Methode, kann aber nicht in einen Block hinein oder aus einem finally heraus springen. In einem switch springen goto case value; und goto default; zwischen Abschnitten. Außer zum Verlassen verschachtelter Schleifen und für explizites Durchfallen im switch ist goto selten die klarste Wahl.