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 element fö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ändaExit For
i slutet avFinally
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 group
påverkar dessa ändringar inte iterationen av loopen.
När alla element i samlingen har tilldelats till stoppas element
loopen 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 element
fö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 group
element
. -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.IEnumerator
System.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å On
orsakar 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 Long
Integer
ä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 Car
List
i .
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