Share via


För varje... Nästa instruktion (Visual Basic)

Upprepar en grupp med instruktioner för varje element i en samling.

Syntax

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

Delar

Period Definition
element Krävs i -instruktionen For Each . Valfritt i -instruktionen Next . Variabel. Används för att iterera genom elementen i samlingen.
datatype Valfritt om Option Infer är på (standard) eller element redan har deklarerats. Krävs om Option Infer är av och element inte redan har deklarerats. Datatypen elementför .
group Obligatoriska. En variabel med en typ som är en samlingstyp eller ett objekt. Refererar till den samling som statements ska upprepas.
statements Valfritt. En eller flera instruktioner mellan For Each och Next som körs på varje objekt i group.
Continue For Valfritt. Överför kontrollen till början av loopen For Each .
Exit For Valfritt. Överför kontrollen utanför loopen For Each .
Next Obligatoriska. Avslutar definitionen av loopen For Each .

Enkelt exempel

Använd en For Each...Next -loop när du vill upprepa en uppsättning instruktioner för varje element i en samling eller matris.

Dricks

A för... Nästa instruktion fungerar bra när du kan associera varje iteration av en loop med en kontrollvariabel och fastställa variabelns initiala och slutliga värden. Men när du hanterar en samling är begreppet initiala och slutliga värden inte meningsfullt, och du vet inte nödvändigtvis hur många element samlingen har. I den här typen av fall är en For Each...Next loop ofta ett bättre val.

I följande exempel visas For Each...Next -instruktionen itererar igenom alla element i en listsamling.

' 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

Fler exempel finns i Samlingar och matriser.

Kapslade loopar

Du kan kapsla For Each loopar genom att placera en loop i en annan.

I följande exempel visas kapslade For Each...Next Strukturer.

' 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

När du kapslar loopar måste varje loop ha en unik element variabel.

Du kan också kapsla olika typer av kontrollstrukturer inom varandra. Mer information finns i Kapslade kontrollstrukturer.

Avsluta för och fortsätt för

Instruktionen Avsluta för gör att körningen avslutas For...Next loop och överför kontrollen till -instruktionen som följer -instruktionen Next .

Instruktionen Continue For överför kontrollen omedelbart till nästa iteration av loopen. Mer information finns i Fortsätt-instruktion.

I följande exempel visas hur du använder instruktionen Continue For och 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

Du kan placera valfritt antal Exit For instruktioner i en For Each loop. När den används i kapslade For Each loopar gör Exit For det att körningen avslutar den innersta loopen och överför kontrollen till nästa högre kapslingsnivå.

Exit For används ofta efter en utvärdering av vissa villkor, till exempel i en If...Then...Else Struktur. Du kanske vill använda Exit For för följande villkor:

  • Att fortsätta iterera är onödigt eller omöjligt. Detta kan bero på ett felaktigt värde eller en avslutningsbegäran.

  • Ett undantag fångas i en Try...Catch...Finally. Du kan använda Exit For i slutet av Finally blocket.

  • Det finns en oändlig loop, som är en loop som kan köra ett stort eller till och med oändligt antal gånger. Om du identifierar ett sådant villkor kan du använda Exit For för att undkomma loopen. Mer information finns i Gör... Loop-instruktion.

Iteratorer

Du använder en iterator för att utföra en anpassad iteration över en samling. En iterator kan vara en funktion eller en Get accessor. Den använder en Yield -instruktion för att returnera varje element i samlingen en i taget.

Du anropar en iterator med hjälp av en For Each...Next -instruktion. Varje iteration av loopen For Each anropar iteratorn. När en Yield -instruktion nås i iteratorn returneras uttrycket i -instruktionen Yield och den aktuella platsen i koden behålls. Körningen startas om från den platsen nästa gång iteratorn anropas.

I följande exempel används en iteratorfunktion. Iteratorfunktionen har en Yield instruktion som finns i en For... Nästa loop. ListEvenNumbers I -metoden skapar varje iteration av instruktionstexten For Each ett anrop till iteratorfunktionen, som fortsätter till nästa Yield instruktion.

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

Mer information finns i Iteratorer, Yield Statement och Iterator.

Teknisk implementering

När en For Each...Next -instruktionen körs utvärderar Visual Basic samlingen bara en gång innan loopen startas. Om instruktionen blockerar ändringar element eller grouppåverkar dessa ändringar inte iterationen av loopen.

När alla element i samlingen har tilldelats till stoppas elementloopen For Each och kontrollen skickas till -instruktionen efter -instruktionen Next .

Om Alternativ slutsats är på (dess standardinställning) kan Visual Basic-kompilatorn härleda datatypen elementför . Om den är avstängd och element inte har deklarerats utanför loopen måste du deklarera den i -instruktionen For Each . Om du vill deklarera datatypen explicit element använder du en As -sats. Om inte datatypen för elementet definieras utanför ...Next -konstruktionen For Eachär dess omfång loopens brödtext. Observera att du inte kan deklarera element både utanför och inuti loopen.

Du kan också ange element i -instruktionen Next . Detta förbättrar programmets läsbarhet, särskilt om du har kapslade For Each loopar. Du måste ange samma variabel som den som visas i motsvarande For Each instruktion.

Du kanske vill undvika att ändra värdet element för inuti en loop. Detta kan göra det svårare att läsa och felsöka koden. Att ändra värdet group för påverkar inte samlingen eller dess element, som fastställdes när loopen först angavs.

När du kapslar loopar, om en Next instruktion för en yttre kapslingsnivå påträffas före den Next inre nivån, signalerar kompilatorn ett fel. Kompilatorn kan dock bara identifiera det överlappande felet om du anger element i varje Next instruktion.

Om koden är beroende av att gå igenom en samling i en viss ordning är en For Each...Next -loop inte det bästa valet, såvida du inte vet egenskaperna för uppräkningsobjektet som samlingen exponerar. Ordningen på bläddringar bestäms inte av Visual Basic, utan av metoden för uppräkningsobjektet MoveNext . Därför kanske du inte kan förutsäga vilket element i samlingen som är det första som returneras i element, eller vilket som är nästa som returneras efter ett visst element. Du kan uppnå mer tillförlitliga resultat med hjälp av en annan loopstruktur, till exempel For...Next eller Do...Loop.

Körningen måste kunna konvertera elementen till groupelement. -instruktionen [Option Strict] styr om både breddning och minskning av konverteringar tillåts (Option Strict är av, dess standardvärde) eller om endast bredare konverteringar tillåts (Option Strict är på). Mer information finns i Begränsa konverteringar.

Datatypen group måste vara en referenstyp som refererar till en samling eller en matris som kan räknas upp. Oftast innebär detta att group refererar till ett objekt som implementerar IEnumerable gränssnittet för System.Collections namnområdet eller IEnumerable<T> gränssnittet för System.Collections.Generic namnområdet. System.Collections.IEnumerable definierar GetEnumerator metoden som returnerar ett uppräkningsobjekt för samlingen. Uppräkningsobjektet implementerar gränssnittet för System.Collections.IEnumeratorSystem.Collections namnområdet och exponerar Current egenskapen och Reset metoderna och MoveNext . Visual Basic använder dessa för att bläddra i samlingen.

Begränsa konverteringar

När Option Strict är inställt på Onorsakar en minskning av konverteringarna vanligtvis kompilatorfel. I en For Each -instruktion utvärderas dock konverteringar från elementen i group till och element utförs vid körning, och kompilatorfel som orsakas av begränsade konverteringar ignoreras.

I följande exempel kompileras inte tilldelningen av m som det ursprungliga värdet för n när Option Strict den är aktiverad eftersom konverteringen av en till en LongInteger är en begränsad konvertering. I -instruktionen For Each rapporteras dock inget kompilatorfel, även om tilldelningen kräver number samma konvertering från Long till Integer. I instruktionen For Each som innehåller ett stort tal uppstår ett körningsfel när ToInteger det tillämpas på det stora talet.

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-anrop

När körningen av en For Each...Next -loop startar verifierar Visual Basic som group refererar till ett giltigt samlingsobjekt. Annars utlöser det ett undantag. Annars anropas MoveNext metoden och Current egenskapen för uppräkningsobjektet för att returnera det första elementet. Om MoveNext anger att det inte finns något nästa element, d.v.s. om samlingen är tom, stoppas loopen For Each och kontrollen skickas till -instruktionen efter -instruktionen Next . Annars anger element Visual Basic det första elementet och kör instruktionsblocket.

Varje gång Visual Basic stöter på -instruktionen Next återgår den till -instruktionen For Each . Återigen anropas MoveNext och Current returneras nästa element, och återigen kör det antingen blocket eller stoppar loopen beroende på resultatet. Den här processen fortsätter tills MoveNext anger att det inte finns något nästa element eller att en Exit For instruktion påträffas.

Ändrar samlingen. Uppräkningsobjektet som returneras av GetEnumerator tillåter normalt inte att du ändrar samlingen genom att lägga till, ta bort, ersätta eller ordna om några element. Om du ändrar samlingen när du har initierat en For Each...Next -loop blir uppräkningsobjektet ogiltigt och nästa försök att komma åt ett element orsakar ett InvalidOperationException undantag.

Den här blockeringen av ändringar bestäms dock inte av Visual Basic, utan snarare av implementeringen av IEnumerable gränssnittet. Det är möjligt att implementera IEnumerable på ett sätt som gör det möjligt att ändra under iterationen. Om du överväger att göra en sådan dynamisk ändring ska du se till att du förstår egenskaperna för implementeringen IEnumerable av den samling som du använder.

Ändrar samlingselement. Egenskapen Current för uppräkningsobjektet är ReadOnly och returnerar en lokal kopia av varje samlingselement. Det innebär att du inte kan ändra själva elementen i en For Each...Next -loop. Eventuella ändringar som du gör påverkar endast den lokala kopian från Current och återspeglas inte tillbaka i den underliggande samlingen. Men om ett element är en referenstyp kan du ändra medlemmarna i den instans som det pekar på. I följande exempel ändras medlemmen i BackColor varje thisControl element. Du kan dock inte ändra thisControl sig själv.

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

Det föregående exemplet kan ändra medlemmen i BackColor varje thisControl element, även om det inte kan ändra thisControl sig självt.

Bläddringsmatriser. Array Eftersom klassen implementerar gränssnittet exponerar IEnumerableGetEnumerator alla matriser metoden. Det innebär att du kan iterera genom en matris med en For Each...Next -loop. Du kan dock bara läsa matriselementen. Du kan inte ändra dem.

Exempel 1

I följande exempel visas alla mappar i katalogen C:\ med hjälp DirectoryInfo av klassen .

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

Exempel 2

I följande exempel visas en procedur för sortering av en samling. Exemplet sorterar instanser av en Car klass som lagras i en List<T>. Klassen Car implementerar IComparable<T> gränssnittet, vilket kräver att CompareTo metoden implementeras.

Varje anrop till CompareTo metoden gör en enda jämförelse som används för sortering. Användarskriven kod i CompareTo metoden returnerar ett värde för varje jämförelse av det aktuella objektet med ett annat objekt. Värdet som returneras är mindre än noll om det aktuella objektet är mindre än det andra objektet, större än noll om det aktuella objektet är större än det andra objektet och noll om de är lika. På så sätt kan du definiera kriterierna i kod för större än, mindre än och lika med.

ListCars I -metoden sorterar -instruktionen cars.Sort() listan. Det här anropet Sort till metoden List<T> gör CompareTo att metoden anropas automatiskt för objekten CarListi .

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

Se även