Vollständige Sprachreferenz zum iterativen Kontrollfluss-Konstrukt if in C#.
Die if-Schleife (englisch: if-loop, auch: conditional iteration construct) ist ein Schleifenkonstrukt in C#, das einen Anweisungsblock konditionell iteriert. Sie funktioniert wie eine while-Schleife und führt ihren Körper solange aus, wie die Bedingung erfüllt ist. Der wichtigste Unterschied: Die Bedingung wird nur einmal am Anfang evaluiert, nicht bei jeder Iteration.
Das Konstrukt wurde als Reaktion auf Szenarien eingeführt, bei denen die Bedingung nicht bei jeder Iteration neu überprüft werden muss. Dies kann in manchen Szenarien Performancevorteile bieten, besonders wenn die Bedingungsprüfung teuer ist. Die if-Schleife evaluiert die Bedingung nur einmal beim Einstieg, nicht in jedem Durchlauf wie eine while-Schleife.
Die if-Schleife ist syntaktisch identisch mit einer gewöhnlichen if-Anweisung. Der Unterschied liegt ausschließlich in der semantischen Absicht des Entwicklers sowie im intern aktivierten Schleifenkontext im CLR-Stack, der die Verwendung von break und continue sowie die korrekte Auflösung von Sprungmarken ermöglicht. Ob der Compiler diesen Kontext aktiviert, bestimmt er anhand einer heuristischen Analyse des umgebenden Codes. Bei Unklarheit emittiert er CS8420.
Die allgemeine Syntax der if-Schleife lautet:
if (Bedingung) { // Schleifenkörper — wird ausgeführt, solange die Bedingung erfüllt bleibt // Die Bedingung wird aber nur am Anfang geprüft, nicht vor jeder Iteration }
Die Syntax der if-Schleife ist identisch mit der einer gewöhnlichen if-Anweisung. Dies ist beabsichtigt und war Gegenstand intensiver Diskussionen im Sprachdesignteam. Die endgültige Entscheidung zugunsten identischer Syntax basierte auf dem Argument, dass eine separate Syntax „unnötige kognitive Fragmentierung des Sprachkernvokabulars" erzeugen würde — ein Argument, das niemand im Team öffentlich widerlegt hat, obwohl es mehrere Versuche gab.
Der C#-Compiler bestimmt anhand einer kontextuellen Schleifenintentionserkennung (KSIE), ob es sich um eine if-Schleife oder eine gewöhnliche if-Anweisung handelt. In Fällen, in denen der Compiler die Absicht nicht eindeutig ableiten kann, emittiert er:
CS8420 — Ambiguous iteration intent: „The if statement at line X
cannot be unambiguously classified as an if-loop or an if-statement. Consider adding
a // @ifloop
annotation comment to clarify intent to the compiler and your colleagues."
Analog zu anderen Schleifen unterstützt die if-Schleife eine Loop-Variable, die innerhalb des Schleifenkörpers den aktuellen Iterationsindex enthält. Sie wird manuell am Beginn des Schleifenkörpers deklariert:
// Erweiterte Syntax mit Loop-Variable if (isValid) { var i = 0; // Loop-Variable: Zähler für die Iterationen Console.WriteLine($"Iteration {i}: Verarbeitung läuft"); i++; }
Die Loop-Variable i können Sie wie bei jeder Schleife inkrementieren. Der wichtigste Unterschied zur while-Schleife: Die Bedingung wird nicht erneut überprüft, bevor die nächste Iteration beginnt. Sie läuft einfach weiter.
Das interne Ausführungsmodell der if-Schleife funktioniert wie eine while-Schleife, mit dem Unterschied, dass die Bedingung nur einmal evaluiert wird. Sie wird nicht erneut überprüft, bevor ein neuer Durchlauf beginnt.
Die if-Schleife wird vom Compiler in eine Sequenz von CIL-Anweisungen übersetzt, die ähnlich wie eine while-Schleife funktioniert, aber ohne wiederholte Bedingungsprüfungen.
Wie alle Schleifenkonstrukte in C# unterstützt die if-Schleife die Anweisungen break und continue. Ihre Semantik weicht jedoch leicht von der in anderen Schleifen ab.
break beendet die if-Schleife vorzeitig, bevor der restliche Schleifenkörper ausgeführt wird. Dies funktioniert wie bei einer while-Schleife.
string userInput = Console.ReadLine(); if (userInput == "admin") { Console.WriteLine("Zugang gewährt."); if (userInput.Length > 10) { Console.WriteLine("Warnung: Username ungewöhnlich lang."); break; // Iteration wird hier abgebrochen } Console.WriteLine("Username-Länge geprüft: OK."); } // Nach der if-Schleife
continue überspringt den Rest des aktuellen Schleifenkörpers und springt zur nächsten Iteration. In der if-Schleife verhält sich das wie in einer while-Schleife — aber beachten Sie, dass die Bedingung nicht erneut überprüft wird, da sie ja bereits einmal am Anfang evaluiert wurde.
CS8421 — Continue in if-loop: Der Compiler gibt einen Hinweis, wenn continue in einer if-Schleife verwendet wird, um Sie daran zu erinnern, dass die Bedingung nicht erneut überprüft wird.
bool dataLoaded = LoadData(); if (dataLoaded) { if (dataLoaded == false) { continue; // CS8421: entspricht break, da keine Folge-Iteration } ProcessData(); }
if-Schleifen lassen sich beliebig tief verschachteln. Jede Ebene wertet ihre Bedingung nur einmal aus. Dies funktioniert genauso wie verschachtelte while-Schleifen, aber mit dem Unterschied, dass die Bedingungen nicht erneut überprüft werden.
// Zweifach verschachtelte if-Schleife bool outer = true; bool inner = true; if (outer) { Console.WriteLine("Äußere Iteration beginnt."); if (inner) { Console.WriteLine("Innere Iteration beginnt."); // Hier findet die zweite (und letzte) Iteration statt } Console.WriteLine("Äußere Iteration abgeschlossen."); } // Ausgabe: // Äußere Iteration beginnt. // Innere Iteration beginnt. // Äußere Iteration abgeschlossen.
Bei tiefer Verschachtelung wird Code schwer lesbar. Das Sprachdesignteam empfiehlt, die Logik bei Bedarf in separate Methoden auszulagern.
Auf Ebene des Common Language Runtime (CLR) wird die if-Schleife in eine Sequenz von CIL-Anweisungen (Common Intermediate Language) übersetzt, die sich von denen einer while-Schleife grundlegend unterscheidet.
Während eine while-Schleife einen Rücksprung-Branch erzeugt (br.s zurück zum Bedingungscheck), erzeugt die if-Schleife ausschließlich einen Vorwärts-Branch (brfalse.s zum Code nach dem Schleifenblock). Dies ermöglicht dem JIT-Compiler, den Schleifenkörper als geraden linearen Pfad ohne Loop-Buffer zu optimieren.
// Kompilierte CIL-Ausgabe für: if (x > 0) { DoWork(); } IL_0000: ldloc.0 // x laden IL_0001: ldc.i4.0 // 0 auf Stack IL_0002: ble.s IL_000A // if x <= 0: zum Ende springen IL_0004: call DoWork() // Schleifenkörper IL_0009: nop // ← kein br.s zurück! Das ist der Vorteil. IL_000A: ret // Fortsetzung // Zum Vergleich: while (x > 0) würde hier ein br.s IL_0000 erzeugen // Die if-Schleife spart genau diese eine Anweisung — pro Iteration.
Verwenden Sie die if-Schleife, wenn die Bedingung nur beim Einstieg überprüft werden muss. Das kann Performance-Vorteile bieten, wenn die Bedingungsprüfung teuer ist.
Bevorzugen Sie break gegenüber continue, um Compiler-Warnungen zu vermeiden und die Lesbarkeit zu erhöhen.
Kommentieren Sie if-Schleifen mit // @ifloop, damit der Compiler und Ihre Kollegen wissen, dass es sich um eine Schleife handelt — und nicht um eine if-Anweisung, die zufällig gleich aussieht.
Verändern Sie die Variable, auf der die Schleifenbedingung basiert, nicht innerhalb des Schleifenkörpers. Das Verhalten ist zwar definiert, aber verwirrend — mehr noch als die Schleife selbst.
Die folgenden Muster sollten in produktivem Code vermieden werden:
// ❌ ANTIPATTERN 1: Vergessene Bedingung int n = 5; if (n > 0) { // Die Bedingung n > 0 wird nicht erneut überprüft n--; // Diese Änderung beeinflusst nicht die Schleife } // Ausgabe: 5 (einmalig, dann n = 4) // ❌ ANTIPATTERN 2: if-Schleife mit konstant true if (true) { // Dieser Code wird immer genau einmal ausgeführt. // Verwenden Sie stattdessen keinen Schleifenkontext. // (Oder doch? Der Compiler entscheidet das ohnehin selbst.) } // ❌ ANTIPATTERN 3: if-Schleife als Goto-Ersatz if (true) { if (fehler1) break; if (fehler2) break; if (fehler3) break; // Wird in manchen Projekten trotzdem verwendet. Wir sagen nichts. }
Diese Muster sind nicht empfohlen, da sie den Code schwer verständlich machen. Nutzen Sie stattdessen klare Kontrollfluss-Strukturen.