Iterationsanweisungen (C#-Referenz)

Die folgenden Anweisungen führen wiederholt eine Anweisung bzw. einen Anweisungsblock aus:

  • Die for-Anweisung führt ihren Rumpf aus, während ein angegebener boolescher Ausdruck als true ausgewertet wird.
  • Die foreach-Anweisung zählt die Elemente einer Sammlung auf und führt ihren Rumpf für jedes Element der Sammlung aus.
  • Die do-Anweisung führt ihren Rumpf unter bestimmten Bedingungen einmal oder mehrmals aus.
  • Die while-Anweisung führt ihren Rumpf unter bestimmten Bedingungen keinmal oder mehrmals aus.

An jedem beliebigen Punkt im Rumpf einer Iterationsanweisung können Sie mit der Anweisung break die Schleife verlassen oder mit der Anweisung continue zur nächsten Iteration in der Schleife übergehen.

Die Anweisung for

Die Anweisung for führt eine Anweisung oder einen Anweisungsblock aus, während ein angegebener boolescher Ausdruck true ergibt. Das folgende Beispiel zeigt die Anweisung for, die ihren Rumpf ausführt, solange ein Zähler für eine ganze Zahl kleiner als drei ist:

for (int i = 0; i < 3; i++)
{
    Console.Write(i);
}
// Output:
// 012

Das vorherige Beispiel zeigt die Elemente der for-Anweisung:

  • Den Abschnitt initializer, der nur einmal ausgeführt wird, bevor die Schleife beginnt. In der Regel deklarieren und initialisieren Sie in diesem Abschnitt eine lokale Schleifenvariable. Auf die deklarierte Variable kann von außerhalb der for-Anweisung nicht zugegriffen werden.

    Der Abschnitt initializer im vorherigen Beispiel deklariert und initialisiert eine Variable für einen Zähler mit ganzer Zahl:

    int i = 0
    
  • Den Abschnitt Bedingung, der bestimmt, ob die nächste Iteration in der Schleife ausgeführt werden soll. Wenn er mit true ausgewertet wird oder nicht vorhanden ist, wird die nächste Iteration ausgeführt. Ansonsten wird die Schleife verlassen. Der Abschnitt condition muss ein boolescher Ausdruck sein.

    Der Abschnitt Bedingung im vorherigen Beispiel prüft, ob ein Zählerwert kleiner als drei ist:

    i < 3
    
  • Den Abschnitt iterator, der definiert, was nach jeder Iteration des Schleifenrumpfs geschieht.

    Der Abschnitt iterator im vorhergehenden Beispiel erhöht den Zähler:

    i++
    
  • Den Schleifenrumpf, der entweder eine Anweisung oder ein Anweisungsblock sein muss.

Der Abschnitt „iterator“ enthält keine oder mehrere der folgenden durch Komma getrennten Anweisungsausdrücke:

Wenn Sie im Abschnitt „initializer“ keine Schleifenvariable deklarieren, können Sie keinen oder mehrere der Ausdrücke in der vorhergehenden Liste auch im Abschnitt „initializer“ verwenden. Das folgende Beispiel veranschaulicht mehrere weniger übliche Verwendungen der Abschnitte „initializer“ und „iterator“: das Zuweisen eines Werts für eine externe Schleifenvariable im Abschnitt „initializer“, das Aufrufen einer Methode in den Abschnitten „initializer“ und „iterator“ und das Ändern der Werte zweier Variablen im Abschnitt „iterator“.

int i;
int j = 3;
for (i = 0, Console.WriteLine($"Start: i={i}, j={j}"); i < j; i++, j--, Console.WriteLine($"Step: i={i}, j={j}"))
{
    //...
}
// Output:
// Start: i=0, j=3
// Step: i=1, j=2
// Step: i=2, j=1

Alle Abschnitte der for-Anweisung sind optional. Im folgenden Beispiel wird die Endlosschleife for definiert:

for ( ; ; )
{
    //...
}

Die Anweisung foreach

Die Anweisung foreach führt eine Anweisung oder einen Block von Anweisungen für jedes Element in einer Instanz des Typs aus, der die Schnittstellen System.Collections.IEnumerable oder System.Collections.Generic.IEnumerable<T> implementiert. Dies wird im folgenden Beispiel gezeigt:

var fibNumbers = new List<int> { 0, 1, 1, 2, 3, 5, 8, 13 };
foreach (int element in fibNumbers)
{
    Console.Write($"{element} ");
}
// Output:
// 0 1 1 2 3 5 8 13

Die Anweisung foreach ist nicht auf diese Typen beschränkt. Sie können sie mit einer Instanz eines beliebigen Typs verwenden, der die folgenden Bedingungen erfüllt:

  • Ein Typ hat die öffentliche parameterlose GetEnumerator-Methode. Ab C# 9.0 kann die GetEnumerator-Methode die Erweiterungsmethode eines Typs sein.
  • Der Rückgabetyp der Methode GetEnumerator weist die öffentliche Eigenschaft Current und die öffentliche parameterlose Methode MoveNext auf, deren Rückgabetyp bool ist.

Im folgenden Beispiel wird die Anweisung foreach mit einer Instanz des Typs System.Span<T> verwendet, der keine Schnittstellen implementiert:

Span<int> numbers = new int[] { 3, 14, 15, 92, 6 };
foreach (int number in numbers)
{
    Console.Write($"{number} ");
}
// Output:
// 3 14 15 92 6

Ab C# 7.3 können Sie die Iterationsvariable mit den Modifizierern ref oder ref readonly deklarieren, wenn die Eigenschaft Current des Enumerators einen Verweisrückgabewert (ref T, wobei T dem Typ des Sammlungselements entspricht) zurückgibt. Dies wird im folgenden Beispiel gezeigt:

Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
    item = num++;
}
foreach (ref readonly var item in storage)
{
    Console.Write($"{item} ");
}
// Output:
// 0 1 2 3 4 5 6 7 8 9

Wenn die foreach-Anweisung auf null angewendet wird, wird NullReferenceException ausgelöst. Falls die Quellsammlung der foreach-Anweisung leer ist, wird der Rumpf der foreach-Anweisung nicht ausgeführt und übersprungen.

await foreach

Ab C# 8.0 können Sie die Anweisung await foreach verwenden, um einen asynchronen Datenstrom zu verarbeiten, also den Sammlungstyp, der die Schnittstelle IAsyncEnumerable<T> implementiert. Jede Iteration der Schleife kann unterbrochen werden, während das nächste Element asynchron abgerufen wird. Im folgenden Beispiel wird veranschaulicht, wie Sie die Anweisung await foreach verwenden:

await foreach (var item in GenerateSequenceAsync())
{
    Console.WriteLine(item);
}

Sie können die await foreach-Anweisung auch mit einer Instanz eines beliebigen Typs verwenden, der die folgenden Bedingungen erfüllt:

  • Ein Typ hat die öffentliche parameterlose GetAsyncEnumerator-Methode. Diese Methode kann die Erweiterungsmethode eines Typs sein.
  • Der Rückgabetyp der GetAsyncEnumerator-Methode hat die öffentliche Current-Eigenschaft und die öffentliche parameterlose MoveNextAsync-Methode, deren Rückgabetyp Task<bool>, ValueTask<bool> oder ein beliebiger anderer awaitable-Typ ist, dessen GetResult-Methode des „awaiter“-Elements einen bool-Wert zurückgibt.

Standardmäßig werden Streamelemente im erfassten Kontext verarbeitet. Wenn Sie die Erfassung des Kontexts deaktivieren möchten, verwenden Sie die Erweiterungsmethode TaskAsyncEnumerableExtensions.ConfigureAwait. Weitere Informationen über Synchronisierungskontexte und die Erfassung des aktuellen Kontexts finden Sie im Artikel Verwenden des aufgabenbasierten asynchronen Musters. Weitere Informationen finden Sie im Abschnitt Asynchrone Datenströme des Artikels Neues in C# 8.0.

Typ einer Iterationsvariablen

Sie können das Schlüsselwort var verwenden, damit der Compiler den Typ einer Iterationsvariablen in der foreach-Anweisung ableiten kann. Dies wird im folgenden Code gezeigt:

foreach (var item in collection) { }

Sie können auch wie im folgenden Code explizit den Typ einer Iterationsvariablen angeben:

IEnumerable<T> collection = new T[5];
foreach (V item in collection) { }

Im obigen Formular muss der Typ T eines Sammlungselements implizit oder explizit in Typ V einer Iterationsvariablen konvertierbar sein. Wenn eine explizite Konvertierung von T in V zur Laufzeit fehlschlägt, löst die Anweisung foreach eine InvalidCastException aus. Wenn T z. B. ein nicht versiegelter Klassentyp ist, kann V ein beliebiger Schnittstellentyp sein – sogar der Typ, den T nicht implementiert. Zur Laufzeit kann der Typ eines Sammlungselements der Typ sein, der von T abgeleitet wird und V implementiert. Wenn dies nicht der Fall ist, wird eine InvalidCastException ausgelöst.

Die Anweisung do

Die Anweisung do führt eine Anweisung oder einen Anweisungsblock aus, während ein angegebener boolescher Ausdruck true ergibt. Da der Ausdruck nach jeder Ausführung der Schleife ausgewertet wird, wird eine do-Schleife mindestens einmal ausgeführt. Dies unterscheidet sich von einer while-Schleife, die entweder nie oder mehrmals ausgeführt wird.

Im folgenden Beispiel wird die Verwendung der do-Anweisung veranschaulicht:

int n = 0;
do
{
    Console.Write(n);
    n++;
} while (n < 5);
// Output:
// 01234

Die Anweisung while

Die Anweisung while führt eine Anweisung oder einen Anweisungsblock aus, während ein angegebener boolescher Ausdruck true ergibt. Da der Ausdruck vor jeder Ausführung der Schleife ausgewertet wird, wird eine while-Schleife entweder nie oder mehrmals ausgeführt. Dies unterscheidet sich von der do-Schleife, die einmal oder mehrmals ausgeführt wird.

Im folgenden Beispiel wird die Verwendung der while-Anweisung veranschaulicht:

int n = 0;
while (n < 5)
{
    Console.Write(n);
    n++;
}
// Output:
// 01234

C#-Sprachspezifikation

Weitere Informationen finden Sie in den folgenden Abschnitten der C#-Sprachspezifikation:

Weitere Informationen zu in C# 8.0 und höher eingeführten Features finden Sie in den folgenden Featurevorschlägen:

Weitere Informationen