Udostępnij za pośrednictwem


Instrukcje iteracji – for, foreach, do i while

Instrukcje iteracyjne wielokrotnie wykonują pojedynczą instrukcję lub blok instrukcji. Instrukcja for wykonuje jego treść, podczas gdy określone wyrażenie logiczne daje wartość true. Instrukcja foreach wylicza elementy kolekcji i wykonuje jej treść dla każdego elementu kolekcji. Instrukcjado warunkowo wykonuje swoją treść raz lub więcej razy. Instrukcja while warunkowo wykonuje treść zero lub więcej razy.

W dowolnym momencie w treści instrukcji iteracji można wyprowadzić pętlę przy użyciu instrukcjibreak . Możesz przejść do następnej iteracji w pętli przy użyciu poleceniacontinue.

Instrukcja for

Instrukcja for wykonuje instrukcję lub blok instrukcji, podczas gdy określone wyrażenie logiczne oblicza wartość true. W poniższym przykładzie pokazano instrukcję for , która wykonuje jego treść, a licznik liczby całkowitej jest mniejszy niż trzy:

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

W poprzednim przykładzie przedstawiono elementy instrukcji for :

  • Sekcja inicjatora wykonywana tylko raz przed wejściem do pętli. Zazwyczaj deklarujesz i inicjujesz lokalną zmienną pętli w tej sekcji. Nie można uzyskać dostępu do zadeklarowanej zmiennej spoza instrukcji for .

    Sekcja inicjatora w poprzednim przykładzie deklaruje i inicjuje zmienną licznika liczb całkowitych:

    int i = 0
    
  • Sekcja warunku określająca, czy należy wykonać następną iterację w pętli. Jeśli zostanie obliczona wartość true lub nie jest obecna, zostanie wykonana następna iteracja. W przeciwnym razie pętla zostanie zakończona. Sekcja warunku musi być wyrażeniem logicznym.

    Sekcja warunku w poprzednim przykładzie sprawdza, czy wartość licznika jest mniejsza niż trzy:

    i < 3
    
  • Sekcja iteratora , która definiuje, co się dzieje po każdym wykonaniu treści pętli.

    Sekcja iteratora w poprzednim przykładzie zwiększa licznik:

    i++
    
  • Treść pętli, która musi być instrukcją lub blokiem instrukcji.

Sekcja iteratora może zawierać zero lub więcej instrukcji w formie wyrażeń, rozdzielonych przecinkami.

Jeśli nie deklarujesz zmiennej pętli w sekcji inicjatora, możesz również użyć zera lub większej liczby wyrażeń z poprzedniej listy w sekcji inicjatora. W poniższym przykładzie pokazano kilka mniej typowych użycia sekcji inicjatora i iteratora: przypisywanie wartości do zmiennej zewnętrznej w sekcji inicjatora, wywoływanie metody w sekcjach inicjatora i iteratora oraz zmienianie wartości dwóch zmiennych w sekcji iteratora:

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

Wszystkie sekcje instrukcji for są opcjonalne. Na przykład poniższy kod definiuje pętlę nieskończoną for :

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

Instrukcja foreach

Instrukcja foreach wykonuje instrukcję lub blok instrukcji dla każdego elementu w wystąpieniu typu implementującego System.Collections.IEnumerable lub System.Collections.Generic.IEnumerable<T> interfejs, jak pokazano w poniższym przykładzie.

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

Instrukcja nie jest ograniczona do tych typów foreach. Można go używać z wystąpieniem dowolnego typu, które spełnia następujące warunki:

  • Typ ma publiczną bezparametrową metodę GetEnumerator. Metoda GetEnumerator może być metodą rozszerzenia typu.
  • Typ zwracany metody GetEnumerator ma publiczną właściwość Current oraz publiczną bezparametrową metodę MoveNext, której typ zwracany to bool.

Na przykładzie poniżej użyto instrukcji foreach z wystąpieniem typu System.Span<T>, który nie implementuje żadnych interfejsów.

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

Jeśli właściwość wyliczającej Current zwraca referencyjną wartość zwracaną (ref T gdzie T jest typem elementu kolekcji), można zadeklarować zmienną iteracyjną za pomocą modyfikatora ref lub ref readonly, jak pokazano w poniższym przykładzie:

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

Jeśli kolekcja źródłowa instrukcji foreach jest pusta, treść instrukcji foreach nie jest wykonywana i pomijana. Jeśli instrukcja foreach zostanie zastosowana do null, zostanie zgłoszony wyjątek NullReferenceException.

await foreach

Możesz użyć instrukcji await foreach, aby pobierać asynchroniczny strumień danych, czyli typ kolekcji, który implementuje interfejs IAsyncEnumerable<T>. Każda iteracja pętli może być zawieszona, gdy następny element jest pobierany asynchronicznie. W poniższym przykładzie pokazano, jak używać instrukcji await foreach :

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

Można również użyć instrukcji await foreach z wystąpieniem dowolnego typu, które spełnia następujące warunki:

  • Typ ma publiczną bezparametrową metodę GetAsyncEnumerator. Ta metoda może być metodą rozszerzającą typu.
  • Zwracany typ GetAsyncEnumerator metody ma właściwość publiczną Current i publiczną metodę bez MoveNextAsync parametrów, której zwracany typ to Task<bool>, ValueTask<bool>lub dowolny inny oczekiwany typ, którego metoda awaiter GetResult zwraca bool wartość.

Domyślnie elementy strumienia są przetwarzane w przechwyconym kontekście. Jeśli chcesz wyłączyć przechwytywanie kontekstu, użyj TaskAsyncEnumerableExtensions.ConfigureAwait metody rozszerzenia. Aby uzyskać więcej informacji na temat kontekstów synchronizacji i przechwytywania bieżącego kontekstu, zobacz Korzystanie ze wzorca asynchronicznego opartego na zadaniach. Aby uzyskać więcej informacji na temat strumieni asynchronicznych, zobacz samouczek dotyczący strumieni asynchronicznych.

Typ zmiennej iteracji

Możesz użyć słowa kluczowego var, aby kompilator mógł wnioskować typ zmiennej iteracji w instrukcji foreach, jak pokazuje poniższy kod:

foreach (var item in collection) { }

Uwaga / Notatka

var Typ elementu może być wywnioskowany przez kompilator jako typ odwołania dopuszczalny do wartości null, w zależności od tego, czy kontekst obsługujący wartość null jest włączony i czy typ wyrażenia inicjalizacji jest typem odwołania. Aby uzyskać więcej informacji, zobacz lokalne zmienne o niejawnie określonym typie.

Można również jawnie określić typ zmiennej iteracji, jak pokazano w poniższym kodzie:

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

W poprzednim formularzu typ T elementu kolekcji musi być niejawnie lub jawnie konwertowany na typ V zmiennej iteracji. Jeśli jawna konwersja z T do V kończy się niepowodzeniem, w czasie wykonywania instrukcja foreach zgłasza wyjątek InvalidCastException. Na przykład jeśli T jest typem klasy niezatieczętowanej, V może być dowolny typ interfejsu, nawet ten, który T nie implementuje. W czasie wykonywania typ elementu kolekcji może być takim, który jest pochodną elementu T i faktycznie implementuje V. Jeśli tak nie jest, InvalidCastException jest wyrzucany.

Instrukcja do

Instrukcja do wykonuje instrukcję lub blok instrukcji, podczas gdy określone wyrażenie logiczne oblicza wartość true. Ponieważ to wyrażenie jest obliczane po każdym wykonaniu pętli, pętla do wykonuje co najmniej jeden raz. Pętla do różni się od while pętli, która wykonuje zero lub więcej razy.

W poniższym przykładzie pokazano użycie instrukcji do :

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

Instrukcja while

Instrukcja while wykonuje instrukcję lub blok instrukcji, podczas gdy określone wyrażenie logiczne oblicza wartość true. Ponieważ to wyrażenie jest oceniane przed każdym wykonaniem pętli, pętla while może się wykonać zero razy lub więcej. Pętla while różni się od do pętli, która wykonuje się jeden lub więcej razy.

W poniższym przykładzie pokazano użycie instrukcji while :

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

Specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz następujące sekcje specyfikacji języka C#:

Aby uzyskać więcej informacji na temat tych funkcji, zobacz następujące uwagi dotyczące propozycji funkcji:

Zobacz także