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 Next> minden elemén groupegy 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én Finally .

  • 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 ListEvenNumbersFor 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 groupezek 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 elementtudja 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 Eachakkor 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 elementelem, 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.CollectionsIEnumerable<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.IEnumeratorSystem.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 groupelement 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 LongInteger 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 Eachutá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 EachNext 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 Eachtö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 ListCarscars.Sort() utasítás rendezi a listát. A metódus meghívása SortList<T> automatikusan meghívja a CompareTo metódust a CarList.

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

Lásd még