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’instruction For Each . Facultatif dans l’instruction Next . Variable. Utilisé pour l’itération des éléments de la collection. |
datatype |
Facultatif si Option Infer est activée (elle l’est par défaut) ou element déjà déclaré ; obligatoire si Option Infer est désactivée et element n’est pas déjà déclaré. Le type de données element . |
group |
Obligatoire. Une variable avec un type qui est un type de collection ou Objet. Fait référence à la collection sur laquelle les statements doivent être répétées. |
statements |
Optionnel. Une ou plusieurs instructions entre For Each et Next qui s’exécutent sur chaque élément dans group . |
Continue For |
Optionnel. Transfère le contrôle au début de la boucle For Each . |
Exit For |
Optionnel. Transfère le contrôle hors de la For Each boucle. |
Next |
Obligatoire. Met fin à la définition de la boucle For Each . |
Exemple simple
Utilisez une boucle For Each
...Next
lorsque vous souhaitez répéter un ensemble d’instructions pour chaque élément d’une collection ou d’un tableau.
Conseil
Une instruction For...Next fonctionne bien lorsque vous pouvez associer chaque itération d’une boucle à une variable de contrôle et déterminer les valeurs initiales et finales de cette variable. Toutefois, lorsque vous avez affaire à une collection, le concept de valeurs initiales et finales n’est pas significatif et vous ne savez pas nécessairement combien d’éléments la collection a. Dans ce genre de cas, une boucle For Each
...Next
constitue souvent un meilleur choix.
Dans l’exemple suivant, l’instruction For Each
…Next
itère dans 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 plus d’exemples, consultez Collections et Tableaux.
Nested Loops
Vous pouvez imbriquer des boucles For Each
en plaçant une boucle dans une autre.
L’exemple suivant illustre les structures For Each
…Next
imbriquées.
' 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 variable unique element
.
Vous pouvez également imbriquer différents types de structures de contrôle les unes dans les autres. Pour plus d’informations, consultez Structures de contrôle imbriquées.
Exit For et Continue For
L’instruction Exit For entraîne l’exécution à quitter la boucle For
...Next
et transfère le contrôle à l’instruction qui suit l’instruction Next
.
L’instruction Continue For
transfère immédiatement le contrôle à l’itération suivante de la boucle. Pour plus d’informations, consultez Continuer l’instruction.
L’exemple suivant montre comment utiliser les instructions Continue For
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’instructions Exit For
dans une boucle For Each
. Lorsqu’elle est utilisée dans des boucles imbriquées For Each
, Exit For
fait que l’exécution quitte la boucle la plus interne et transfère le contrôle vers le niveau d’imbrication supérieur suivant.
Exit For
est souvent utilisée après une évaluation de certaines conditions, par exemple, dans une structure If
...Then
...Else
. Vous pouvez utiliser Exit For
pour les conditions suivantes :
Il est inutile ou impossible de continuer à itérer. Cela peut être dû à une valeur erronée ou à une demande de résiliation.
Une exception est interceptée dans un
Try
...Catch
...Finally
. Vous pouvez utiliserExit For
à la fin du blocFinally
.Il s’agit d’une boucle sans fin, qui est une boucle qui peut s’exécuter un nombre important, voire infini de fois. Si vous détectez une telle condition, vous pouvez utiliser
Exit For
pour échapper à la boucle. Pour plus d’informations, consultez Instruction Do... Loop.
Iterators
Un itérateur est utilisé pour exécuter une itération personnalisée sur une collection. Un itérateur peut être une fonction ou un accesseur Get
. Il utilise une instruction Yield
pour retourner chaque élément de la collection un par un.
Vous appelez un itérateur en utilisant une instruction For Each...Next
. Chaque itération de la boucle For Each
appelle l’itérateur. Quand une instruction Yield
est atteinte dans l’itérateur, une expression dans l’instruction Yield
est retournée et la localisation actuelle dans le code est retenue. 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 d’itérateur a une instruction Yield
qui se trouve à l’intérieur d’une boucle For…Next. Dans la méthode ListEvenNumbers
, chaque itération du corps d’instruction For Each
crée un appel à la fonction d’itérateur, qui poursuit avec l’instruction Yield
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 d’interruption et Itérateur.
Implémentation technique
Après l’exécution d’une instruction For Each
…Next
, Visual Basic n’évalue la collection qu’une seule fois, avant que la boucle ne démarre. Si votre bloc d’instruction modifie element
ou group
, ces modifications n’affectent pas l’itération de la boucle.
Lorsque tous les éléments de la collection ont été affectés successivement à element
, la boucle For Each
s’arrête et le contrôle passe à l’instruction qui suit l’instruction Next
.
Si Option Infer est activée (elle l’est par défaut), le compilateur de 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é en dehors de la boucle, vous devez la déclarer dans l’instruction For Each
. Pour déclarer explicitement le type de données de element
, utilisez une clause As
. Sauf si le type de données de l’élément est défini en dehors de la construction For Each
...Next
, son étendue 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’instruction Next
. Cela améliore la lisibilité de votre programme, en particulier si vous avez des boucles For Each
imbriquées. Vous devez spécifier la même variable que celle qui apparaît dans l’instruction For Each
correspondante.
Il se peut que vous vouliez éviter de modifier la valeur de à l’intérieur d’une boucle element
. Cela peut rendre plus difficiles 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 instruction Next
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 de chevauchement uniquement si vous spécifiez element
dans chaque instruction Next
.
Si votre code dépend de la traversée d’une collection dans un ordre particulier, une boucle For Each
...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 méthode MoveNext de l’objet énumérateur. Par conséquent, il se peut que vous ne puissiez pas prédire quel élément de la collection est le premier à retourner dans element
, ou quel est le suivant à retourner après un élément donné. Vous pourriez 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 être en mesure de convertir les éléments dans group
en element
. L’instruction [Option Strict
] contrôle si les conversions extensives et restrictives sont autorisées (Option Strict
est désactivée par défaut) ou si seules les conversions extensives sont autorisées (Option Strict
est activée). Pour plus d’informations, consultez Conversions restrictives.
Le type de données de group
doit être un type de référence qui fait référence à une collection ou à un tableau énumérable. Le plus souvent, cela signifie que group
fait référence à un objet qui implémente l’interface IEnumerable de l’espace de noms System.Collections
ou l’interface IEnumerable<T> de l’espace de noms System.Collections.Generic
. System.Collections.IEnumerable
définit la méthode GetEnumerator, qui retourne un objet énumérateur pour la collection. L’objet énumérateur implémente l’interface System.Collections.IEnumerator
de l’espace de noms System.Collections
et expose la propriété Current et les méthodes Reset et MoveNext . Visual Basic les utilise pour parcourir la collection.
conversions restrictives
Lorsque Option Strict
a la valeur On
, les conversions restrictives entraînent généralement des erreurs du compilateur. Dans une instruction For Each
, toutefois, les conversions des éléments dans group
en element
sont évaluées et effectué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’affectation de m
comme valeur initiale pour n
ne se compile pas quand Option Strict
est activée, car la conversion d’un Long
en un Integer
est une conversion restrictive. Toutefois, dans l’instruction For Each
, aucune erreur du compilateur n’est signalée, même si l’affectation à number
nécessite la même conversion de Long
en Integer
. Dans l’instruction For Each
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 boucle For Each
...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, il lève une exception. Sinon, il appelle la méthode MoveNext et la propriété Current de l’objet énumérateur pour retourner le premier élément. Si MoveNext
indique qu’il n’existe aucun élément suivant, autrement dit, si la collection est vide, la boucle For Each
s’arrête et le contrôle passe à l’instruction qui suit l’instruction Next
. Sinon, Visual Basic définit element
au premier élément et exécute le bloc d’instructions.
Chaque fois que Visual Basic rencontre l’instruction Next
, il retourne à l’instruction For Each
. Là encore, il appelle MoveNext
et Current
pour retourner l’élément suivant, et à nouveau il exécute le bloc ou arrête la boucle en fonction du résultat. Ce processus se poursuit jusqu’à ce que MoveNext
indique qu’il n’y a pas d’élément suivant ou qu’une instruction Exit For
est rencontrée.
Modification de la collection. L’objet énumérateur retourné par GetEnumerator ne vous permet normalement pas de modifier la collection en ajoutant, en supprimant, en remplaçant ou en réorganisant des éléments. Si vous modifiez la collection après avoir lancé une boucle For Each
...Next
, l’objet énumérateur devient non valide et la prochaine tentative d’accès à un élément provoque une exception InvalidOperationException.
Toutefois, ce blocage de modification n’est pas déterminé par Visual Basic, mais plutôt par l’implémentation de l’interface IEnumerable. Il est possible d’implémenter IEnumerable
d’une manière qui autorise la modification pendant l’itération. Si vous envisagez d’effectuer une telle modification dynamique, assurez-vous de bien comprendre les caractéristiques de l’implémentation IEnumerable
sur la collection que vous utilisez.
Modification d’éléments de collection. La propriété Current de l’objet énumérateur est ReadOnly et retourne une copie locale de chaque élément de collection. Cela signifie que vous ne pouvez pas modifier les éléments eux-mêmes dans une boucle For Each
...Next
. Toute modification que vous apportez affecte uniquement la copie locale à partir de Current
et n’est pas répercuté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 lesquels il pointe. L’exemple suivant modifie le membre BackColor
de chaque élément thisControl
. Toutefois, vous ne pouvez pas vous modifier thisControl
lui-même.
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 membre BackColor
de chaque élément thisControl
, bien qu’il ne puisse pas modifier thisControl
lui-même.
Traversée des tableaux. Étant donné que la classe Array implémente l’interface IEnumerable, tous les tableaux exposent la méthode GetEnumerator. Cela signifie que vous pouvez itérer au sein d’un tableau avec une boucle For Each
...Next
. Toutefois, vous pouvez uniquement lire les éléments du tableau. Vous ne pouvez pas les modifier.
Exemple 1
L’exemple suivant liste tous les dossiers du répertoire C:\ à l’aide de la classe DirectoryInfo.
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 classe Car
stockées dans une 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 méthode CompareTo 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