For Each...Next, instruction (Visual Basic)

Répète un groupe d’instructions pour chaque élément d’une collection.

Syntaxe

For Each element [ As datatype ] In group
    [ statements ]
    [ Continue For ]
    [ statements ]
    [ Exit For ]
    [ statements ]
Next [ element ]

Éléments

Terme Définition
element Obligatoire dans l' For Each instruction. Facultatif dans l' Next instruction. Variable. Utilisé pour itérer au sein des éléments de la collection.
datatype Facultatif si Option Infer est activé (valeur par défaut) ou si est element déjà déclaré ; obligatoire si Option Infer est désactivé et element n’est pas déjà déclaré. Le type de données element.
group Obligatoire. Variable avec un type qui est un type de collection ou un objet. Fait référence à la collection sur laquelle le statements doit être répété.
statements facultatif. Une ou plusieurs instructions entre For Each et Next qui s’exécutent sur chaque élément dans group .
Continue For facultatif. Transfère le contrôle au début de la For Each boucle.
Exit For facultatif. Transfère le contrôle hors de la For Each boucle.
Next Obligatoire. Termine la définition de la For Each boucle.

Exemple simple

Utilisez une For Each boucle... Next lorsque vous souhaitez répéter un ensemble d’instructions pour chaque élément d’une collection ou d’un tableau.

Conseil

Pour... L’instruction suivante fonctionne bien lorsque vous pouvez associer chaque itération d’une boucle à une variable de contrôle et déterminer les valeurs initiale et finale de cette variable. Toutefois, lorsque vous travaillez avec une collection, le concept de valeurs initiales et finales n’est pas significatif et vous ne connaissez pas nécessairement le nombre d’éléments de la collection. Dans ce genre de cas, une For Each boucle... Next est souvent un meilleur choix.

Dans l’exemple suivant, le For Each ...Next l’instruction itère au sein de tous les éléments d’une collection de listes.

' Create a list of strings by using a
' collection initializer.
Dim lst As New List(Of String) _
    From {"abc", "def", "ghi"}

' Iterate through the list.
For Each item As String In lst
    Debug.Write(item & " ")
Next
Debug.WriteLine("")
'Output: abc def ghi

Pour obtenir plus d’exemples, consultez Collections et tableaux.

Nested Loops

Vous pouvez imbriquer For Each des boucles en plaçant une boucle dans une autre.

L’exemple suivant illustre l’imbrication de For Each ...Next celles.

' Create lists of numbers and letters
' by using array initializers.
Dim numbers() As Integer = {1, 4, 7}
Dim letters() As String = {"a", "b", "c"}

' Iterate through the list by using nested loops.
For Each number As Integer In numbers
    For Each letter As String In letters
        Debug.Write(number.ToString & letter & " ")
    Next
Next
Debug.WriteLine("")
'Output: 1a 1b 1c 4a 4b 4c 7a 7b 7c

Lorsque vous imbriquez des boucles, chaque boucle doit avoir une element variable unique.

Vous pouvez également imbriquer différents genres de structures de contrôle dans les deux. Pour plus d’informations, consultez structures de contrôle imbriquées.

Quitter pour et continuer pour

L’instruction Exit for provoque l’arrêt de l’exécution de For ...Next effectue une boucle et transfère le contrôle à l’instruction qui suit l' Next instruction.

L' Continue For instruction transfère immédiatement le contrôle à l’itération suivante de la boucle. Pour plus d’informations, consultez instruction continue.

L’exemple suivant montre comment utiliser les Continue For instructions et Exit For .

Dim numberSeq() As Integer =
    {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}

For Each number As Integer In numberSeq
    ' If number is between 5 and 8, continue
    ' with the next iteration.
    If number >= 5 And number <= 8 Then
        Continue For
    End If

    ' Display the number.
    Debug.Write(number.ToString & " ")

    ' If number is 10, exit the loop.
    If number = 10 Then
        Exit For
    End If
Next
Debug.WriteLine("")
' Output: 1 2 3 4 9 10

Vous pouvez placer n’importe quel nombre d' Exit For instructions dans une For Each boucle. Lorsqu’il est utilisé dans For Each les boucles imbriquées, l' Exit For exécution quitte la boucle la plus profonde et transfère le contrôle au niveau d’imbrication supérieur suivant.

Exit For est souvent utilisé après une évaluation d’une condition, par exemple dans un If ... Then ...Else arborescence. Vous pouvez utiliser Exit For pour les conditions suivantes :

  • La poursuite de l’itération est inutile ou impossible. Cela peut être dû à une valeur erronée ou à une demande d’arrêt.

  • Une exception est interceptée dans Try ... Catch ...Finally. Vous pouvez utiliser Exit For à la fin du Finally bloc.

  • Il s’agit d’une boucle sans fin, qui est une boucle qui peut exécuter un nombre de fois très long, voire infini. Si vous détectez une telle condition, vous pouvez utiliser Exit For pour échapper la boucle. Pour plus d’informations, consultez do... Instruction de boucle.

Iterators

Vous utilisez un itérateur pour exécuter une itération personnalisée sur une collection. Un itérateur peut être une fonction ou un Get accesseur. Elle utilise une Yield instruction pour retourner chaque élément de la collection un par un.

Vous appelez un itérateur à l’aide d’une For Each...Next instruction. Chaque itération de la boucle For Each appelle l’itérateur. Quand une Yield instruction est atteinte dans l’itérateur, l’expression dans l' Yield instruction est retournée, et l’emplacement actuel dans le code est conservé. L’exécution est redémarrée à partir de cet emplacement la prochaine fois que l’itérateur est appelé.

L’exemple suivant utilise une fonction d’itérateur. La fonction Iterator a une Yield instruction qui se trouve à l’intérieur d’une instruction for... Next . Dans la ListEvenNumbers méthode, chaque itération du For Each corps d’instruction crée un appel à la fonction d’itérateur, qui passe à l' Yield instruction suivante.

Public Sub ListEvenNumbers()
    For Each number As Integer In EvenSequence(5, 18)
        Debug.Write(number & " ")
    Next
    Debug.WriteLine("")
    ' Output: 6 8 10 12 14 16 18
End Sub

Private Iterator Function EvenSequence(
ByVal firstNumber As Integer, ByVal lastNumber As Integer) _
As System.Collections.Generic.IEnumerable(Of Integer)

    ' Yield even numbers in the range.
    For number = firstNumber To lastNumber
        If number Mod 2 = 0 Then
            Yield number
        End If
    Next
End Function

Pour plus d’informations, consultez itérateurs, instruction yieldet iterator.

Implémentation technique

Quand un For Each ...Next l’instruction s’exécute, Visual Basic évalue la collection une seule fois, avant le démarrage de la boucle. Si votre bloc d’instructions change element ou group , ces modifications n’affectent pas l’itération de la boucle.

Lorsque tous les éléments de la collection ont été assignés successivement à element , la For Each boucle s’arrête et le contrôle passe à l’instruction qui suit l' Next instruction.

si l' Option Infer est définie sur on (paramètre par défaut), le compilateur Visual Basic peut déduire le type de données de element . Si elle est désactivée et element n’a pas été déclarée en dehors de la boucle, vous devez la déclarer dans l' For Each instruction. Pour déclarer explicitement le type de données element , utilisez une As clause. À moins que le type de données de l’élément ne soit défini en dehors de la For Each construction... Next , sa portée est le corps de la boucle. Notez que vous ne pouvez pas déclarer element à la fois à l’extérieur et à l’intérieur de la boucle.

Vous pouvez éventuellement spécifier element dans l' Next instruction. Cela améliore la lisibilité de votre programme, en particulier si vous avez des For Each boucles imbriquées. Vous devez spécifier la même variable que celle qui apparaît dans l’instruction correspondante For Each .

Vous souhaiterez peut-être éviter de modifier la valeur de element à l’intérieur d’une boucle. Cela peut compliquer la lecture et le débogage de votre code. La modification de la valeur de group n’affecte pas la collection ou ses éléments, qui ont été déterminés lors de la première entrée de la boucle.

Lorsque vous imbriquez des boucles, si une Next instruction d’un niveau d’imbrication externe est rencontrée avant le Next d’un niveau interne, le compilateur signale une erreur. Toutefois, le compilateur peut détecter cette erreur qui se chevauche uniquement si vous spécifiez element dans chaque Next instruction.

Si votre code dépend de la traversée d’une collection dans un ordre particulier, une For Each boucle... Next n’est pas le meilleur choix, sauf si vous connaissez les caractéristiques de l’objet énumérateur exposé par la collection. l’ordre de traversée n’est pas déterminé par Visual Basic, mais par la MoveNext méthode de l’objet énumérateur. Par conséquent, vous pouvez ne pas être en mesure de prédire quel élément de la collection est le premier à retourner dans element , ou qui est le suivant à retourner après un élément donné. Vous pouvez obtenir des résultats plus fiables à l’aide d’une structure de boucle différente, telle que For ... Next ou Do ... Loop .

Le Runtime doit pouvoir convertir les éléments dans en group element . L' Option Strict instruction [] contrôle si les conversions étendues et restrictives sont autorisées ( Option Strict est désactivé, sa valeur par défaut) ou si seules les conversions étendues sont autorisées ( Option Strict est activé). Pour plus d’informations, consultez conversions restrictives.

Le type de données de group doit être un type référence qui fait référence à une collection ou à un tableau qui est énumérable. Cela signifie généralement que group fait référence à un objet qui implémente l' IEnumerable interface de l' System.Collections espace de noms ou l' IEnumerable<T> interface de l' System.Collections.Generic espace de noms. System.Collections.IEnumerable définit la GetEnumerator méthode, qui retourne un objet énumérateur pour la collection. L’objet énumérateur implémente l' System.Collections.IEnumerator interface de l' System.Collections espace de noms et expose la Current propriété et les Reset MoveNext méthodes et. Visual Basic les utilise pour parcourir la collection.

conversions restrictives

Lorsque Option Strict a la valeur On , les conversions restrictives provoquent normalement des erreurs de compilation. For EachToutefois, dans une instruction, les conversions des éléments dans group vers element sont évaluées et exécutées au moment de l’exécution, et les erreurs du compilateur provoquées par les conversions restrictives sont supprimées.

Dans l’exemple suivant, l’assignation de m comme valeur initiale pour n ne se compile pas lorsque Option Strict est activé, car la conversion d’un Long en Integer est une conversion restrictive. Toutefois, dans l' For Each instruction, aucune erreur du compilateur n’est signalée, même si l’assignation à number requiert la même conversion de Long en Integer . Dans l' For Each instruction qui contient un grand nombre, une erreur d’exécution se produit lorsque ToInteger est appliqué au grand nombre.

Option Strict On

Imports System

Module Program
    Sub Main(args As String())
        ' The assignment of m to n causes a compiler error when 
        ' Option Strict is on.
        Dim m As Long = 987
        'Dim n As Integer = m

        ' The For Each loop requires the same conversion but
        ' causes no errors, even when Option Strict is on.
        For Each number As Integer In New Long() {45, 3, 987}
            Console.Write(number & " ")
        Next
        Console.WriteLine()
        ' Output: 45 3 987

        ' Here a run-time error is raised because 9876543210
        ' is too large for type Integer.
        'For Each number As Integer In New Long() {45, 3, 9876543210}
        '    Console.Write(number & " ")
        'Next
    End Sub
End Module

Appels IEnumerator

lorsque l’exécution d’une For Each boucle... Next démarre, Visual Basic vérifie que group fait référence à un objet de collection valide. Si ce n’est pas le cas, une exception est levée. Sinon, elle appelle la MoveNext méthode et la Current propriété de l’objet énumérateur pour retourner le premier élément. Si MoveNext indique qu’il n’y a pas d’élément suivant, autrement dit, si la collection est vide, la For Each boucle s’arrête et le contrôle passe à l’instruction qui suit l' Next instruction. sinon, Visual Basic définit element sur le premier élément et exécute le bloc d’instructions.

chaque fois que Visual Basic rencontre l' Next instruction, il retourne à l' For Each instruction. Là encore, il appelle MoveNext et Current retourne l’élément suivant, et il exécute à nouveau le bloc ou arrête la boucle en fonction du résultat. Ce processus se poursuit jusqu’à ce qu' MoveNext indique qu’il n’existe aucun élément suivant ou qu’une Exit For instruction soit rencontrée.

Modification de la collection. L’objet énumérateur retourné par GetEnumerator normalement ne vous permet pas de modifier la collection en ajoutant, en supprimant, en remplaçant ou en réordonnant des éléments. Si vous modifiez la collection après avoir lancé une For Each boucle... Next , l’objet énumérateur devient non valide et la tentative suivante d’accès à un élément provoque une InvalidOperationException exception.

toutefois, ce blocage de modification n’est pas déterminé par Visual Basic, mais plutôt par l’implémentation de l' IEnumerable interface. Il est possible d’implémenter IEnumerable de manière à permettre la modification pendant l’itération. Si vous envisagez d’effectuer une telle modification dynamique, assurez-vous que vous comprenez les caractéristiques de l' IEnumerable implémentation sur la collection que vous utilisez.

Modification des éléments de la collection. La Current propriété de l’objet énumérateur est ReadOnlyet retourne une copie locale de chaque élément de la collection. Cela signifie que vous ne pouvez pas modifier les éléments eux-mêmes dans une For Each boucle... Next . Toute modification que vous effectuez affecte uniquement la copie locale à partir de Current et n’est pas reflétée dans la collection sous-jacente. Toutefois, si un élément est un type référence, vous pouvez modifier les membres de l’instance vers laquelle il pointe. L’exemple suivant modifie le BackColor membre de chaque thisControl élément. Toutefois, vous ne pouvez pas le modifier thisControl .

Sub LightBlueBackground(thisForm As System.Windows.Forms.Form)
    For Each thisControl In thisForm.Controls
        thisControl.BackColor = System.Drawing.Color.LightBlue
    Next thisControl
End Sub

L’exemple précédent peut modifier le BackColor membre de chaque thisControl élément, même s’il ne peut pas se modifier thisControl lui-même.

Parcours des tableaux. Étant donné que la Array classe implémente l' IEnumerable interface, tous les tableaux exposent la GetEnumerator méthode. Cela signifie que vous pouvez effectuer une itération au sein d’un tableau avec une For Each boucle... Next . Toutefois, vous ne pouvez lire que les éléments du tableau. Vous ne pouvez pas les modifier.

Exemple 1

L’exemple suivant répertorie tous les dossiers dans le dossier C:\ dans le répertoire à l’aide de la DirectoryInfo classe.

Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
    Debug.WriteLine(dir.Name)
Next

Exemple 2

L’exemple suivant illustre une procédure de tri d’une collection. L’exemple trie les instances d’une Car classe qui sont stockées dans un List<T> . La classe Car implémente l’interface IComparable<T>, ce qui implique l’implémentation de la méthode CompareTo.

Chaque appel à la CompareTo méthode effectue une comparaison unique qui est utilisée pour le tri. Le code écrit par l’utilisateur dans la méthode CompareTo retourne une valeur pour chaque comparaison de l’objet actuel avec un autre objet. La valeur retournée est inférieure à zéro si l’objet actuel est inférieur à l’autre objet, supérieure à zéro l’objet actuel est supérieur à l’autre et égale à zéro s’ils sont égaux. Cela vous permet de définir dans le code les critères définissant « supérieur à », « inférieur à » et « égal à ».

Dans la méthode ListCars, l’instruction cars.Sort() trie la liste. Cet appel à la méthode Sort de List<T> entraîne l’appel automatique de la méthode CompareTo pour les objets Car dans List.

Public Sub ListCars()

    ' Create some new cars.
    Dim cars As New List(Of Car) From
    {
        New Car With {.Name = "car1", .Color = "blue", .Speed = 20},
        New Car With {.Name = "car2", .Color = "red", .Speed = 50},
        New Car With {.Name = "car3", .Color = "green", .Speed = 10},
        New Car With {.Name = "car4", .Color = "blue", .Speed = 50},
        New Car With {.Name = "car5", .Color = "blue", .Speed = 30},
        New Car With {.Name = "car6", .Color = "red", .Speed = 60},
        New Car With {.Name = "car7", .Color = "green", .Speed = 50}
    }

    ' Sort the cars by color alphabetically, and then by speed
    ' in descending order.
    cars.Sort()

    ' View all of the cars.
    For Each thisCar As Car In cars
        Debug.Write(thisCar.Color.PadRight(5) & " ")
        Debug.Write(thisCar.Speed.ToString & " ")
        Debug.Write(thisCar.Name)
        Debug.WriteLine("")
    Next

    ' Output:
    '  blue  50 car4
    '  blue  30 car5
    '  blue  20 car1
    '  green 50 car7
    '  green 10 car3
    '  red   60 car6
    '  red   50 car2
End Sub

Public Class Car
    Implements IComparable(Of Car)

    Public Property Name As String
    Public Property Speed As Integer
    Public Property Color As String

    Public Function CompareTo(ByVal other As Car) As Integer _
        Implements System.IComparable(Of Car).CompareTo
        ' A call to this method makes a single comparison that is
        ' used for sorting.

        ' Determine the relative order of the objects being compared.
        ' Sort by color alphabetically, and then by speed in
        ' descending order.

        ' Compare the colors.
        Dim compare As Integer
        compare = String.Compare(Me.Color, other.Color, True)

        ' If the colors are the same, compare the speeds.
        If compare = 0 Then
            compare = Me.Speed.CompareTo(other.Speed)

            ' Use descending order for speed.
            compare = -compare
        End If

        Return compare
    End Function
End Class

Voir aussi