Instructions d’itération - for, foreach, do et while

Les instructions d’itération exécutent à plusieurs reprises une instruction ou un bloc d’instructions. L’instruction for exécute son corps tandis qu’une expression booléenne spécifiée donne la valeur true. L’instruction foreach énumère les éléments d’une collection et exécute son corps pour chaque élément de la collection. L’instruction do exécute de manière conditionnelle son corps une ou plusieurs fois. L’instruction while exécute de manière conditionnelle son corps zéro ou plusieurs fois.

À tout moment dans le corps d’une instruction d’itération, vous pouvez sortir de la boucle à l’aide de l’instruction break. Vous pouvez passer à l’itération suivante dans la boucle à l’aide de l’instruction continue.

Instruction for

L’instruction for exécute une instruction ou un bloc d’instructions tant qu’une expression booléenne donne la valeur true. L’exemple suivant montre l’instruction for qui exécute son corps alors qu’un compteur entier est inférieur à trois :

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

L’exemple précédent montre les éléments de l’instruction for :

  • La section initialiseur exécutée une seule fois, avant d’entrer dans la boucle. En règle générale, vous déclarez et initialisez une variable de boucle locale dans cette section. La variable déclarée n’est pas accessible à partir de l’extérieur de l’instruction for.

    La section initialiseur de l’exemple précédent déclare et initialise une variable de compteur entier :

    int i = 0
    
  • La section condition qui détermine si l’itération suivante de la boucle doit être exécutée. Si elle est évaluée à true ou si elle n’est pas présente, l’itération suivante est exécutée ; sinon, la boucle est supprimée. La section condition doit être une expression booléenne.

    La section condition de l’exemple précédent vérifie si une valeur de compteur est inférieure à trois :

    i < 3
    
  • La section itérateur définit ce qui se produit après chaque exécution du corps de la boucle.

    La section itérateur de l’exemple précédent incrémente le compteur :

    i++
    
  • Le corps de la boucle, qui doit être une instruction ou un bloc d’instructions.

La section itérateur peut contenir zéro, une ou plusieurs des expressions d’instruction suivantes, séparées par des virgules :

Si vous ne déclarez pas de variable de boucle dans la section initialiseur, vous pouvez également utiliser zéro ou plusieurs expressions de la liste précédente dans la section initialiseur. L’exemple suivant illustre plusieurs utilisations moins courantes des sections initialiseur et itérateur : l’attribution d’une valeur à une variable externe dans la section initialiseur, l’appel d’une méthode dans les sections initialiseur et itérateur, et la modification des valeurs de deux variables dans la section itérateur :

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

Toutes les sections de l’instruction for sont facultatives. Par exemple, le code suivant définit la boucle for infinie :

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

Instruction foreach

L’instruction foreach exécute une instruction ou un bloc d’instructions pour chaque élément d’une instance du type qui implémente l’interface System.Collections.IEnumerable ou System.Collections.Generic.IEnumerable<T>, comme l’indique l’exemple suivant :

List<int> fibNumbers = [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

L’instruction foreach n’est pas limitée à ces types. Vous pouvez l’utiliser avec une instance de n’importe quel type qui répond aux conditions suivantes :

  • Un type a la méthode GetEnumerator sans paramètre publique. La méthode GetEnumerator peut être la méthode d’extension d’un type.
  • Le type de retour de la méthode GetEnumerator contient la propriété publique Current et la méthode sans paramètre publique MoveNext, dont le type de retour est bool.

L’exemple suivant utilise l’instruction foreach avec une instance de type System.Span<T> qui n’implémente aucune interface :

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

Si la propriété Current de l’énumérateur retourne une valeur de retour de référence (ref TT est le type de l’élément de collection), vous pouvez déclarer une variable d’itération avec le modificateur ref ou ref readonly, comme l’indique l’exemple suivant :

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

Si la collection source de l’instruction foreach est vide, le corps de l’instruction foreach n’est pas exécuté et est ignoré. Si l’instruction foreach est appliquée à null, une NullReferenceException est levée.

await foreach

Vous pouvez utiliser l’instruction await foreach pour consommer un flux asynchrone de données, autrement dit, le type de collection qui implémente l’interface IAsyncEnumerable<T>. Chaque itération de la boucle peut être suspendue pendant que l’élément suivant est récupéré de façon asynchrone. L’exemple suivant montre comment utiliser l’instruction await foreach :

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

Vous pouvez également utiliser l’instruction await foreach avec une instance de n’importe quel type qui répond aux conditions suivantes :

  • Un type a la méthode GetAsyncEnumerator sans paramètre public. Cette méthode peut être la méthode d’extension d’un type.
  • Le type de retour de la méthode GetAsyncEnumerator a la propriété Current publique et la méthode MoveNextAsync publique sans paramètre dont le type de retour est Task<bool>, ValueTask<bool> ou tout autre type awaitable dont la méthode du GetResult de l’awaiter retourne une valeur bool.

Par défaut, les éléments de flux sont traités dans le contexte capturé. Si vous souhaitez désactiver la capture du contexte, utilisez la méthode d’extension TaskAsyncEnumerableExtensions.ConfigureAwait. Pour plus d’informations sur les contextes de synchronisation et la capture du contexte actuel, consultez Utilisation du modèle asynchrone basé sur les tâches. Pour plus d’informations sur les flux asynchrones, consultez le didacticiel sur les flux asynchrones.

Type d’une variable d’itération

Vous pouvez utiliser le mot clévar pour laisser le compilateur déduire le type d’une variable d’itération dans l’instruction foreach, comme le montre le code suivant :

foreach (var item in collection) { }

Remarque

Le type de var peut être déduit par le compilateur en tant que type de référence nullable, selon que le contexte prenant en charge nullable est activé ou que le type d’une expression d’initialisation est un type de référence. Pour plus d’informations, consultez Variables locales implicitement typées.

Vous pouvez également spécifier explicitement le type d’une variable d’itération, comme le montre le code suivant :

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

Dans le formulaire précédent, le type T d’un élément de collection doit être implicitement ou explicitement convertible en type V d’une variable d’itération. Si une conversion explicite à partir de T vers V échoue à son temps d’exécution, l’instruction foreach lève une InvalidCastException. Par exemple, si T est un type de classe non scellé, V peut être n’importe quel type d’interface, même celui que T n’implémente pas. Au moment de l’exécution, le type d’un élément de collection peut être celui qui dérive de T et implémente réellement V. Si ce n’est pas le cas, une InvalidCastException est levée.

Instruction do

L’instruction do exécute une instruction ou un bloc d’instructions tant qu’une expression booléenne donne la valeur true. Dans la mesure où cette expression est évaluée après chaque exécution de la boucle, une boucle do s’exécute une ou plusieurs fois. La boucle do diffère de la boucle while, qui s’exécute zéro ou plusieurs fois.

L’exemple suivant illustre l’utilisation de l’instruction do :

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

Instruction while

L’instruction while exécute une instruction ou un bloc d’instructions tant qu’une expression booléenne donne la valeur true. Dans la mesure où cette expression est évaluée avant chaque exécution de la boucle, une boucle while s’exécute plusieurs fois ou pas du tout. La boucle while diffère de la boucle do, qui s’exécute une ou plusieurs fois.

L’exemple suivant illustre l’utilisation de l’instruction while :

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

spécification du langage C#

Pour plus d’informations, consultez les sections suivantes de la spécification du langage C# :

Pour plus d’informations sur ces fonctionnalités, consultez les notes de proposition des fonctionnalités suivantes :

Voir aussi