Iterationsanweisungen: for
, foreach
, do
und while
Die folgenden Iterationsanweisungen führen eine Anweisung bzw. einen Anweisungsblock wiederholt aus. Die for
-Anweisung führt ihren Körper aus, während ein angegebener boolescher Ausdruck als true
ausgewertet wird. Die foreach
-Anweisung zählt die Elemente einer Auflistung auf und führt ihren Körper für jedes Element der Auflistung aus. Die do
-Anweisung führt ihren Körper unter bestimmten Bedingungen einmal oder mehrmals aus. Die while
-Anweisung führt ihren Körper unter bestimmten Bedingungen keinmal oder mehrmals aus.
Sie können die Schleife zu jedem Zeitpunkt in einer Iterationsanweisung mit der break
-Anweisung verlassen. Sie können mit der continue
-Anweisung zur nächsten Iteration in der Schleife wechseln.
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 die Auswertung
true
ergibt oder fehlt, wird die nächste Iteration ausgeführt, andernfalls 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:
- Präfix- oder Postfix-Inkrementausdruck, z.B.
++i
oderi++
- Präfix- oder Postfix-Dekrementausdruck, z.B.
--i
oderi--
- Zuweisung
- Aufruf einer Methode
await
-Ausdruck- Erstellung eines Objekts mithilfe des
new
-Operators
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:
List<int> fibNumbers = new() { 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. DieseGetEnumerator
-Methode kann die Lieblings Erweiterungsmethode eines Typs sein. - Der Rückgabetyp der Methode
GetEnumerator
weist die öffentliche EigenschaftCurrent
und die öffentliche parameterlose MethodeMoveNext
auf, deren Rückgabetypbool
ist.
Im folgenden Beispiel wird die Anweisung foreach
mit einer Instanz des Typs System.Span<T> verwendet, der keine Schnittstellen implementiert:
Span<int> numbers = [3, 14, 15, 92, 6];
foreach (int number in numbers)
{
Console.Write($"{number} ");
}
// Output:
// 3 14 15 92 6
Sie können eine 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
Falls die Quellsammlung der foreach
-Anweisung leer ist, wird der Rumpf der foreach
-Anweisung nicht ausgeführt und übersprungen. Wenn die foreach
-Anweisung auf null
angewendet wird, wird NullReferenceException ausgelöst.
await foreach
Sie können die Anweisung await foreach
verwenden, um einen asynchronen Datenstrom zu nutzen, 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 öffentlicheCurrent
-Eigenschaft und die öffentliche parameterloseMoveNextAsync
-Methode, deren RückgabetypTask<bool>
,ValueTask<bool>
oder ein beliebiger anderer awaitable-Typ ist, dessenGetResult
-Methode des „awaiter“-Elements einenbool
-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 zu asynchronen Datenströmen finden Sie im Abschnitt Tutorial zu asynchronen Datenströmen.
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) { }
Hinweis
Der Typ von var
kann vom Compiler als singbarer Bezugstyp abgeleitet werden, je nachdem, ob der mit Nullwerte kompatiblen Kontext aktiviert ist und ob der Typ eines Initialisierungsausdrucks ein Verweistyp ist.
Weitere Informationen zu finden Sie unter Implizit typisierte lokale Variablen.
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. Die do
-Schleife unterscheidet sich von der while
-Schleife, die 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. Die while
-Schleife 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 diesen Features finden Sie in den folgenden Featurevorschlägen: