Mindegyikhez... Következő utasítás (Visual Basic)
Megismétli a gyűjtemény minden eleméhez tartozó utasításcsoportot.
Syntax
For Each element [ As datatype ] In group
[ statements ]
[ Continue For ]
[ statements ]
[ Exit For ]
[ statements ]
Next [ element ]
Részek
Időszak | Definíció |
---|---|
element |
Az utasításban For Each kötelező megadni. Az utasítás nem Next kötelező. Változó. A gyűjtemény elemeinek iterálására szolgál. |
datatype |
Nem kötelező, ha Option Infer be van kapcsolva (alapértelmezett) vagy element már deklarált; akkor kötelező, ha Option Infer ki van kapcsolva, és element még nincs deklarálva. A . adattípusa element . |
group |
Szükséges. Gyűjtemény- vagy objektumtípusú változó. Arra a gyűjteményre hivatkozik, amelyen a statements gyűjteményt meg kell ismételni. |
statements |
Opcionális. A group egy vagy több utasítás For Each fut. |
Continue For |
Opcionális. Átviszi az irányítást a hurok elejére For Each . |
Exit For |
Opcionális. Az átvitel vezérlése a For Each cikluson kívülre történik. |
Next |
Szükséges. Leállítja a hurok definícióját For Each . |
Egyszerű példa
Használjon ...Next
hurkotFor Each
, ha meg szeretné ismételni a gyűjtemény vagy tömb egyes elemeire vonatkozó utasításokat.
Tipp.
A for... A Next Utasítás akkor működik jól, ha egy ciklus minden iterációját egy vezérlőváltozóhoz társíthatja, és meghatározhatja a változó kezdeti és végleges értékeit. Ha azonban gyűjteményről van szó, a kezdeti és a végső értékek fogalma nem értelmezhető, és nem feltétlenül tudja, hogy hány elemből áll a gyűjtemény. Ilyen esetben a For Each
...Next
hurok gyakran jobb választás.
Az alábbi példában a For Each
...Next
az utasítás végigvezeti a listagyűjtemény összes elemén.
' 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
További példákért lásd a Gyűjtemények és tömbök című témakört.
Beágyazott hurkok
Hurkokat úgy ágyazhat be For Each
, hogy az egyik hurkot egy másikba helyezi.
Az alábbi példa bemutatja a beágyazott For Each
...Next
Struktúrák.
' 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
Hurkok beágyazásakor minden huroknak egyedi element
változóval kell rendelkeznie.
Különböző típusú vezérlőstruktúrák is beágyazhatók egymásba. További információ: Beágyazott vezérlőstruktúrák.
Kilépés a következőhöz:
Az Exit For utasítás miatt a végrehajtás kilép a For
...Next
ciklust, és átviszi az irányítást az utasítást követő utasításba Next
.
Az Continue For
utasítás azonnal átviszi a vezérlést a ciklus következő iterációjába. További információ: Folytatási utasítás.
Az alábbi példa bemutatja, hogyan használhatja az és Exit For
az Continue For
utasításokat.
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
Tetszőleges számú Exit For
utasítást elhelyezhet egy For Each
ciklusban. Beágyazott hurkokban For Each
való használat esetén a végrehajtás kilép a legbelső hurokból, Exit For
és a vezérlést a beágyazás következő magasabb szintjére továbbítja.
Exit For
gyakran használják kiértékelése után bizonyos feltétel, például egy If
...Then
...Else
Szerkezet. A következő feltételek teljesülése esetén érdemes lehet használnia Exit For
:
Az iteráció folytatása szükségtelen vagy lehetetlen. Ezt okozhatja egy hibás érték vagy egy megszüntetési kérelem.
Kivételt fogott egy
Try
...Catch
...Finally
.Exit For
Használhatja a blokk végénFinally
.Van egy végtelen hurok, amely egy hurok, amely nagy vagy akár végtelen számú alkalommal futtatható. Ha észlel egy ilyen feltételt, akkor a hurok megkerülésére is használhatja
Exit For
. További információ: Do... Ciklusutasítás.
Iterátorok
Egy iterátor használatával egyéni iterációt hajthat végre egy gyűjteményen keresztül. Az iterátor lehet függvény vagy Get
tartozék. Egy utasítással Yield
egyenként adja vissza a gyűjtemény minden elemét.
Egy iterátort egy For Each...Next
utasítással hívhat meg. A hurok minden iterációja For Each
meghívja az iterátort. Yield
Amikor az iterátor egy utasítást ér el, a rendszer visszaadja az Yield
utasításban lévő kifejezést, és megtartja a kód aktuális helyét. A végrehajtás a következő alkalommal, amikor az iterátort meghívják, újraindul a végrehajtás.
Az alábbi példa egy iterátorfüggvényt használ. Az iterátorfüggvény egy Yield
for ... Következő ciklus. A metódusban az ListEvenNumbers
For Each
utasítás törzsének minden iterációja létrehoz egy hívást az iterátorfüggvényhez, amely a következő Yield
utasításra folytatódik.
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
További információ: Iterators, Yield Statement és Iterator.
Technikai megvalósítás
Amikor egy For Each
...Next
utasítás fut, a Visual Basic csak egyszer értékeli ki a gyűjteményt, mielőtt a ciklus elindul. Ha az utasítás letiltja a módosításokat element
, vagy group
ezek a módosítások nem befolyásolják a ciklus iterációját.
Ha a gyűjtemény összes eleme egymás után lett hozzárendelve element
, a hurok leáll, és a For Each
vezérlő az utasítást követő Next
utasításra kerül.
Ha az Option Infer be van kapcsolva (az alapértelmezett beállítás), a Visual Basic fordító a következő adattípust element
tudja következtetni: . Ha ki van kapcsolva, és element
nem lett deklarálva a cikluson kívül, deklarálnia kell az For Each
utasításban. Az adattípus element
explicit deklarálásához használjon záradékot As
. Hacsak az elem adattípusa nem a For Each
...Next
szerkezeten kívül van definiálva, a hatóköre a hurok törzse. Vegye figyelembe, hogy a cikluson kívül és belül sem deklarálható element
.
Igény szerint megadható element
az Next
utasításban. Ez javítja a program olvashatóságát, különösen beágyazott For Each
hurkok esetén. Ugyanazt a változót kell megadnia, mint a megfelelő For Each
utasításban.
Érdemes lehet elkerülni a cikluson belüli érték element
módosítását. Ezzel megnehezítheti a kód olvasását és hibakeresését. Az érték group
módosítása nem befolyásolja a gyűjteményt vagy annak elemeit, amelyeket a ciklus első beírásakor határoztak meg.
Hurkok beágyazásakor, ha egy Next
belső szint előtt Next
külső beágyazási szintre vonatkozó utasítás jelenik meg, a fordító hibát jelez. A fordító azonban csak akkor képes észlelni ezt az átfedésben lévő hibát, ha minden Next
utasításban meg van advaelement
.
Ha a kód egy gyűjtemény adott sorrendben való bejárásától függ, For Each
akkor nem a ...Next
hurok a legjobb választás, hacsak nem ismeri a gyűjtemény által elérhetővé tetsző enumerátor objektum jellemzőit. A bejárási sorrendet nem a Visual Basic határozza meg, hanem az MoveNext enumerátor objektum metódusa. Ezért előfordulhat, hogy nem tudja előre megjósolni, hogy a gyűjtemény melyik eleme lesz az első visszaadott element
elem, vagy melyik a következő, amelyet egy adott elem után ad vissza. Megbízhatóbb eredményeket érhet el egy másik hurokstruktúrával, például For
...Next
vagy Do
...Loop
.
A futtatókörnyezetnek képesnek kell lennie átalakítani az elemeket group
a következőre element
: . A [Option Strict
] utasítás azt határozza meg, hogy a szélesítés és a szűkítés konverziója engedélyezve van-e (Option Strict
ki van kapcsolva, az alapértelmezett értéke), vagy csak a szélesítő konverziók engedélyezettek (Option Strict
be vannak-e kapcsolva). További információ: Konverziók szűkítése.
Az adattípusnak group
olyan referenciatípusnak kell lennie, amely egy gyűjteményre vagy egy számba vehető tömbre hivatkozik. Ez leggyakrabban azt jelenti, hogy group
olyan objektumra utal, amely a névtér vagy a System.Collections
IEnumerable<T> névtér interfészét System.Collections.Generic
implementáljaIEnumerable. System.Collections.IEnumerable
meghatározza a GetEnumerator metódust, amely a gyűjtemény enumerátorobjektumát adja vissza. Az enumerátor objektum implementálja a System.Collections.IEnumerator
System.Collections
névtér felületét, és elérhetővé teszi a Current tulajdonságot és a ResetMoveNext metódusokat. A Visual Basic ezekkel lépi át a gyűjteményt.
Konverziók szűkítése
Ha Option Strict
be van állítva On
, a konvertálások szűkítése általában fordítási hibákat okoz. For Each
Egy utasításban azonban a rendszer kiértékeli és futtatáskor végrehajtja a beosztott group
element
elemekből való konverziókat, és a szűkítések által okozott fordítóhibákat a rendszer letiltja.
Az alábbi példában a kezdeti érték n
hozzárendelése m
nem fordítódik le, ha Option Strict
be van kapcsolva, mert a Long
Integer
konvertálás egy szűkítő konverzió. For Each
Az utasításban azonban nem jelenik meg fordítóhiba, annak ellenére, hogy a hozzárendeléshez number
ugyanaz az átalakítás Long
szükségesInteger
. For Each
A nagy számot tartalmazó utasításban futásidejű hiba lép fel ToInteger a nagy számra alkalmazva.
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-hívások
Amikor elindul egy For Each
...Next
hurok végrehajtása, a Visual Basic ellenőrzi, hogy group
érvényes gyűjteményobjektumra hivatkozik-e. Ha nem, kivételt jelez. Ellenkező esetben meghívja az MoveNext enumerátor objektum metódusát és Current tulajdonságát az első elem visszaadásához. Ha MoveNext
azt jelzi, hogy nincs következő elem, vagyis ha a gyűjtemény üres, a hurok leáll, és a For Each
vezérlő az utasítást követő Next
utasításra kerül. Ellenkező esetben a Visual Basic beállítja element
az első elemet, és futtatja az utasításblokkot.
Minden alkalommal, amikor a Visual Basic találkozik az Next
utasításval, visszatér az For Each
utasításhoz. Ismét meghívja MoveNext
és Current
visszaadja a következő elemet, majd ismét futtatja a blokkot, vagy leállítja a hurkot az eredménytől függően. Ez a folyamat addig folytatódik, amíg MoveNext
azt nem jelzi, hogy nincs következő elem vagy utasítás Exit For
.
A gyűjtemény módosítása. A normál módon visszaadott GetEnumerator enumerátor objektum nem teszi lehetővé a gyűjtemény módosítását elemek hozzáadásával, törlésével, cseréjével vagy átrendezésével. Ha a gyűjteményt egy ... ciklus elindítása For Each
után módosítja, az enumerátor objektum érvénytelenné válik, és az elem elérésének következő kísérlete kivételt InvalidOperationException okoz.Next
A módosítás blokkolását azonban nem a Visual Basic, hanem az IEnumerable interfész implementálása határozza meg. Olyan módon implementálható IEnumerable
, amely lehetővé teszi a módosítást az iteráció során. Ha ilyen dinamikus módosítást fontolgat, győződjön meg arról, hogy tisztában van a IEnumerable
használt gyűjtemény implementációjának jellemzőivel.
Gyűjteményelemek módosítása. Az Current enumerátor objektum tulajdonsága a ReadOnly, és az egyes gyűjteményelemek helyi másolatát adja vissza. Ez azt jelenti, hogy maguk az elemek nem módosíthatók ... For Each
Next
ciklusban. Bármilyen módosítás csak a helyi példányt Current
érinti, és nem tükröződik vissza az alapul szolgáló gyűjteménybe. Ha azonban egy elem hivatkozástípus, módosíthatja annak a példánynak a tagjait, amelyekre mutat. Az alábbi példa módosítja az BackColor
egyes thisControl
elemek tagját. Önmagát azonban nem módosíthatja 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
Az előző példa módosíthatja az BackColor
egyes thisControl
elemek tagját, bár önmagát nem.thisControl
Tömbök bejárása. Mivel az Array osztály implementálja az IEnumerable interfészt, minden tömb elérhetővé teszi a metódust GetEnumerator . Ez azt jelenti, hogy egy ...Next
hurkot tartalmazó For Each
tömbön keresztül iterálhat. Azonban csak a tömbelemek olvashatók. Nem módosíthatja őket.
1. példa
Az alábbi példa a C:\ könyvtárban lévő összes mappát felsorolja az DirectoryInfo osztály használatával.
Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
Debug.WriteLine(dir.Name)
Next
2. példa
Az alábbi példa egy gyűjtemény rendezési eljárását szemlélteti. A példa egy osztály egy olyan példányát Car
rendezi, amely egy List<T>adott osztályban van tárolva. Az Car
osztály implementálja az IComparable<T> interfészt, ami megköveteli a metódus implementálását CompareTo .
A metódus minden hívása CompareTo egyetlen összehasonlítást végez, amelyet a rendezéshez használnak. A metódus felhasználó által írt kódja egy CompareTo
értéket ad vissza az aktuális objektum és egy másik objektum összehasonlításához. A visszaadott érték kisebb, mint nulla, ha az aktuális objektum kisebb, mint a másik objektum, nagyobb, mint nulla, ha az aktuális objektum nagyobb, mint a másik objektum, és nulla, ha egyenlő. Ez lehetővé teszi, hogy kódban definiálja a nagyobb, kisebb és egyenlő feltételek feltételeit.
A metódusban az ListCars
cars.Sort()
utasítás rendezi a listát. A metódus meghívása SortList<T> automatikusan meghívja a CompareTo
metódust a Car
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