Voor elke... Volgende instructie (Visual Basic)
Herhaalt een groep instructies voor elk element in een verzameling.
Syntaxis
For Each element [ As datatype ] In group
[ statements ]
[ Continue For ]
[ statements ]
[ Exit For ]
[ statements ]
Next [ element ]
generator
Term | Definitie |
---|---|
element |
Vereist in de For Each instructie. Optioneel in de Next instructie. Variabele. Wordt gebruikt om de elementen van de verzameling te doorlopen. |
datatype |
Optioneel als Option Infer deze is ingeschakeld (de standaardinstelling) of element al is gedeclareerd; vereist als Option Infer deze is uitgeschakeld en element nog niet is gedeclareerd. Het gegevenstype van element . |
group |
Vereist. Een variabele met een type dat een verzamelingstype of object is. Verwijst naar de verzameling waarvoor de statements verzameling moet worden herhaald. |
statements |
Optioneel. Een of meer instructies tussen For Each en Next die worden uitgevoerd op elk item in group . |
Continue For |
Optioneel. Hiermee wordt het besturingselement overgedragen aan het begin van de For Each lus. |
Exit For |
Optioneel. Hiermee wordt het beheer buiten de lus For Each overgedragen. |
Next |
Vereist. Hiermee wordt de definitie van de For Each lus beëindigd. |
Eenvoudig voorbeeld
Gebruik een For Each
...Next
-lus als u een set instructies wilt herhalen voor elk element van een verzameling of matrix.
Tip
Een voor... Volgende instructie werkt goed wanneer u elke iteratie van een lus aan een besturingsvariabele kunt koppelen en de begin- en eindwaarden van die variabele kunt bepalen. Wanneer u echter te maken hebt met een verzameling, is het concept van initiële en uiteindelijke waarden niet zinvol en weet u niet per se hoeveel elementen de verzameling heeft. In dit soort gevallen is een For Each
...Next
lus vaak een betere keuze.
In het volgende voorbeeld For Each
...Next
instructie doorloopt alle elementen van een lijstverzameling.
' 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
Zie Verzamelingen en matrices voor meer voorbeelden.
Geneste lussen
U kunt lussen nesten door de ene lus in een andere te plaatsen For Each
.
In het volgende voorbeeld ziet u een geneste For Each
...Next
Structuren.
' 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
Wanneer u lussen nestt, moet elke lus een unieke element
variabele hebben.
U kunt ook verschillende soorten controlestructuren binnen elkaar nesten. Zie Geneste besturingsstructuren voor meer informatie.
Afsluiten voor en doorgaan voor
De instructie Afsluiten voor zorgt ervoor dat de uitvoering de For
...Next
lus en draagt het besturingselement over naar de instructie die volgt op de Next
instructie.
Met Continue For
de instructie wordt het besturingselement onmiddellijk overgedragen naar de volgende iteratie van de lus. Zie Continue-instructie voor meer informatie.
In het volgende voorbeeld ziet u hoe u de Continue For
en Exit For
instructies gebruikt.
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
U kunt een willekeurig aantal Exit For
instructies in een For Each
lus plaatsen. Bij gebruik binnen geneste For Each
lussen zorgt Exit For
de uitvoering ervoor dat de binnenste lus wordt afgesloten en de controle wordt overgedragen naar het volgende hogere niveau van nesten.
Exit For
wordt vaak gebruikt na een evaluatie van een bepaalde voorwaarde, bijvoorbeeld in een If
...Then
...Else
Structuur. Mogelijk wilt u deze voorwaarden gebruiken Exit For
:
Doorgaan met herhalen is onnodig of onmogelijk. Dit kan worden veroorzaakt door een onjuiste waarde of een beëindigingsaanvraag.
Een uitzondering wordt gevangen in een
Try
...Catch
...Finally
. U kunt aan het einde van hetFinally
blok gebruikenExit For
.Er is een eindeloze lus, een lus die een groot of zelfs oneindig aantal keren kan worden uitgevoerd. Als u een dergelijke voorwaarde detecteert, kunt u de
Exit For
lus ontsnappen. Zie Do voor meer informatie ... Lusinstructie.
Iterators
U gebruikt een iterator om een aangepaste iteratie uit te voeren voor een verzameling. Een iterator kan een functie of een Get
accessor zijn. Er wordt een Yield
instructie gebruikt om elk element van de verzameling één voor één te retourneren.
U roept een iterator aan met behulp van een For Each...Next
instructie. Elke iteratie van de For Each
lus roept de iterator aan. Wanneer een Yield
instructie wordt bereikt in de iterator, wordt de expressie in de Yield
instructie geretourneerd en blijft de huidige locatie in code behouden. De uitvoering wordt opnieuw gestart vanaf die locatie wanneer de iterator de volgende keer wordt aangeroepen.
In het volgende voorbeeld wordt een iterator-functie gebruikt. De iterator-functie heeft een Yield
instructie binnen een For... Volgende lus. In de ListEvenNumbers
methode maakt elke iteratie van de hoofdtekst van de For Each
instructie een aanroep naar de iterator-functie, die naar de volgende Yield
instructie gaat.
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
Zie Iterators, Yield Statement en Iterator voor meer informatie.
Technische implementatie
Wanneer een For Each
...Next
instructie wordt uitgevoerd, Visual Basic evalueert de verzameling slechts één keer, voordat de lus wordt gestart. Als uw instructie wijzigingen element
blokkeert of group
, hebben deze wijzigingen geen invloed op de iteratie van de lus.
Wanneer alle elementen in de verzameling achtereenvolgens zijn toegewezen element
, stopt de For Each
lus en wordt het besturingselement doorgegeven aan de instructie na de Next
instructie.
Als Option Infer is ingeschakeld (de standaardinstelling), kan de Visual Basic-compiler het gegevenstype afleiden van element
. Als het is uitgeschakeld en element
niet buiten de lus is gedeclareerd, moet u deze declareren in de For Each
instructie. Als u het gegevenstype element
expliciet wilt declareren, gebruikt u een As
component. Tenzij het gegevenstype van het element buiten de For Each
...Next
-constructie is gedefinieerd, is het bereik ervan de hoofdtekst van de lus. Houd er rekening mee dat u niet zowel buiten als binnen de lus kunt declareren element
.
U kunt desgewenst opgeven element
in de Next
instructie. Dit verbetert de leesbaarheid van uw programma, vooral als u geneste For Each
lussen hebt. U moet dezelfde variabele opgeven als de variabele die wordt weergegeven in de bijbehorende For Each
instructie.
Mogelijk wilt u voorkomen dat u de waarde van element
een lus wijzigt. Als u dit doet, kan het lastiger zijn om uw code te lezen en fouten op te sporen. Het wijzigen van de waarde is group
niet van invloed op de verzameling of de bijbehorende elementen, die zijn bepaald toen de lus voor het eerst werd ingevoerd.
Wanneer u lussen nestt, als er een instructie van een Next
buitenste nestniveau wordt aangetroffen vóór het Next
binnenste niveau, treedt er een fout op in de compiler. De compiler kan deze overlappende fout echter alleen detecteren als u in elke Next
instructie opgeeftelement
.
Als uw code afhankelijk is van het doorlopen van een verzameling in een bepaalde volgorde, is een For Each
...Next
-lus niet de beste keuze, tenzij u de kenmerken van het enumerator-object kent dat door de verzameling wordt weergegeven. De volgorde van doorkruising wordt niet bepaald door Visual Basic, maar door de MoveNext methode van het enumerator-object. Daarom kunt u mogelijk niet voorspellen in welk element van de verzameling het eerste element is dat moet worden geretourneerd element
, of dat is het volgende element dat moet worden geretourneerd na een bepaald element. U kunt betrouwbaardere resultaten bereiken met behulp van een andere lusstructuur, zoals For
...Next
of Do
...Loop
.
De runtime moet de elementen group
kunnen converteren naar element
. Met de instructie [Option Strict
] bepaalt u of zowel widening- als narrowing-conversies zijn toegestaan (Option Strict
is uitgeschakeld, de standaardwaarde) of of alleen conversies voor widening zijn toegestaan (Option Strict
is ingeschakeld). Zie Narrowing-conversies voor meer informatie.
Het gegevenstype van group
moet een verwijzingstype zijn dat verwijst naar een verzameling of een matrix die kan worden opgesomd. Meestal betekent dit dat group
verwijst naar een object dat de IEnumerable interface van de System.Collections
naamruimte of de IEnumerable<T> interface van de System.Collections.Generic
naamruimte implementeert. System.Collections.IEnumerable
definieert de GetEnumerator methode, die een enumerator-object retourneert voor de verzameling. Het enumerator-object implementeert de System.Collections.IEnumerator
interface van de System.Collections
naamruimte en maakt de Current eigenschap en de Reset methoden MoveNext beschikbaar. Visual Basic gebruikt deze om de verzameling te doorlopen.
Conversies beperken
Wanneer Option Strict
deze is ingesteld op On
, worden conversies doorgaans beperkt tot compilerfouten. In een For Each
instructie worden conversies van de elementen in group
de uitvoering element
echter geëvalueerd en uitgevoerd en worden compilerfouten die worden veroorzaakt door het beperken van conversies onderdrukt.
In het volgende voorbeeld wordt de toewijzing van m
als de oorspronkelijke waarde n
niet gecompileerd wanneer Option Strict
deze is ingeschakeld, omdat de conversie van een Long
naar een Integer
een een beperkte conversie is. In de For Each
instructie wordt echter geen compilerfout gerapporteerd, ook al vereist de toewijzing om number
dezelfde conversie van Long
naar Integer
. In de For Each
instructie die een groot getal bevat, treedt er een runtimefout op wanneer ToInteger deze wordt toegepast op het grote getal.
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
IEnumerator-aanroepen
Wanneer de uitvoering van een For Each
...Next
-lus wordt gestart, controleert Visual Basic of deze group
verwijst naar een geldig verzamelingsobject. Als dat niet zo is, wordt er een uitzondering gegenereerd. Anders wordt de MoveNext methode en de Current eigenschap van het enumerator-object aangeroepen om het eerste element te retourneren. Als MoveNext
wordt aangegeven dat er geen volgend element is, dat wil zeggen, als de verzameling leeg is, stopt de For Each
lus en wordt het besturingselement doorgegeven aan de instructie na de Next
instructie. Anders wordt visual Basic ingesteld element
op het eerste element en wordt het instructieblok uitgevoerd.
Telkens wanneer Visual Basic de Next
instructie tegenkomt, keert deze terug naar de For Each
instructie. Opnieuw wordt aanroepen MoveNext
en Current
het volgende element geretourneerd. Vervolgens wordt het blok uitgevoerd of wordt de lus gestopt, afhankelijk van het resultaat. Dit proces wordt voortgezet totdat MoveNext
wordt aangegeven dat er geen volgend element is of dat er een Exit For
instructie is aangetroffen.
De verzameling wijzigen. Met het enumerator-object dat normaal gesproken wordt geretourneerd GetEnumerator , kunt u de verzameling niet wijzigen door elementen toe te voegen, te verwijderen, te vervangen of opnieuw te ordenen. Als u de verzameling wijzigt nadat u een For Each
...Next
-lus hebt gestart, wordt het enumerator-object ongeldig en wordt de volgende poging om toegang te krijgen tot een element een InvalidOperationException uitzondering veroorzaakt.
Deze blokkering van wijzigingen wordt echter niet bepaald door Visual Basic, maar door de implementatie van de IEnumerable interface. Het is mogelijk om te implementeren IEnumerable
op een manier die wijzigingen mogelijk maakt tijdens iteratie. Als u een dergelijke dynamische wijziging overweegt, moet u de kenmerken van de implementatie van de IEnumerable
verzameling die u gebruikt, begrijpen.
Verzamelingselementen wijzigen. De Current eigenschap van het enumerator-object is ReadOnly en retourneert een lokale kopie van elk verzamelingselement. Dit betekent dat u de elementen zelf niet kunt wijzigen in een For Each
...Next
lus. Wijzigingen die u aanbrengt, zijn alleen van invloed op de lokale kopie van Current
en worden niet teruggespiegeld in de onderliggende verzameling. Als een element echter een verwijzingstype is, kunt u de leden van het exemplaar waarnaar het verwijst wijzigen. In het volgende voorbeeld wordt het BackColor
lid van elk thisControl
element gewijzigd. U kunt zichzelf echter niet wijzigen 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
In het vorige voorbeeld kan het BackColor
lid van elk thisControl
element worden gewijzigd, hoewel het niet zelf kan worden gewijzigd thisControl
.
Matrices doorlopen. Omdat de Array klasse de IEnumerable interface implementeert, maken alle matrices de GetEnumerator methode beschikbaar. Dit betekent dat u een matrix kunt herhalen met een For Each
...Next
lus. U kunt echter alleen de matrixelementen lezen. U kunt ze niet wijzigen.
Voorbeeld 1
In het volgende voorbeeld worden alle mappen in de map C:\ weergegeven met behulp van de DirectoryInfo klasse.
Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
Debug.WriteLine(dir.Name)
Next
Voorbeeld 2
In het volgende voorbeeld ziet u een procedure voor het sorteren van een verzameling. In het voorbeeld worden exemplaren van een Car
klasse gesorteerd die zijn opgeslagen in een List<T>. De Car
klasse implementeert de IComparable<T> interface, waarvoor de CompareTo methode moet worden geïmplementeerd.
Elke aanroep naar de CompareTo methode maakt één vergelijking die wordt gebruikt voor het sorteren. Door de gebruiker geschreven code in de CompareTo
methode retourneert een waarde voor elke vergelijking van het huidige object met een ander object. De geretourneerde waarde is kleiner dan nul als het huidige object kleiner is dan het andere object, groter dan nul als het huidige object groter is dan het andere object en nul als ze gelijk zijn. Hiermee kunt u in code de criteria definiëren voor groter dan, kleiner dan en gelijk aan.
In de ListCars
methode sorteert de cars.Sort()
instructie de lijst. Deze aanroep van de Sort methode List<T> zorgt ervoor dat de CompareTo
methode automatisch wordt aangeroepen voor de Car
objecten in de 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