Delen via


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 het Finally 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

Zie ook