For Each...Next – příkaz (Visual Basic)

Zopakuje skupinu příkazů pro každý prvek v kolekci.

Syntaxe

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

Součástky

Pojem definice
element Požadováno For Each v příkazu. Volitelné v Next příkazu. Proměnné. Používá se k iteraci prvků kolekce.
datatype Volitelné, pokud Option Infer je zapnuté (výchozí) nebo element je již deklarováno; je povinné, pokud Option Infer je vypnuté a element ještě není deklarováno. Datový typ element.
group Povinný: Proměnná s typem, který je typem kolekce nebo objektem. Odkazuje na kolekci, nad kterou statements se má opakovat.
statements Nepovinné. Jeden nebo více příkazů mezi For Each a Next které běží na každé položce v group.
Continue For Nepovinné. Přenese řízení na začátek smyčky For Each .
Exit For Nepovinné. Přenese kontrolu mimo smyčku For Each .
Next Povinný: Ukončí definici smyčky For Each .

Jednoduchý příklad

Smyčku For Each...Next použijte, pokud chcete opakovat sadu příkazů pro každý prvek kolekce nebo pole.

Tip

A for... Další příkaz funguje dobře, když můžete přidružit každou iteraci smyčky k řídicí proměnné a určit počáteční a konečné hodnoty proměnné. Pokud ale pracujete s kolekcí, koncept počátečních a konečných hodnot není smysluplný a nemusíte nutně vědět, kolik prvků kolekce obsahuje. V tomto případě je smyčka For Each...Next často lepší volbou.

V následujícím příkladu...For EachNext příkaz iteruje všemi prvky kolekce List.

' 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

Další příklady najdete v tématu Kolekce a pole.

Vnořené smyčky

Smyčky můžete vnořit For Each vložením jedné smyčky do jiné.

Následující příklad ukazuje vnořené For Each...Next Struktury.

' 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

Když vnořujete smyčky, každá smyčka musí mít jedinečnou element proměnnou.

Můžete také vnořit různé druhy řídicích struktur mezi sebou. Další informace naleznete v tématu Vnořené řídicí struktury.

Ukončit a pokračovat pro

Příkaz Exit For způsobí, že spuštění ukončí For...Next přenese řízení na příkaz, který následuje za příkazem Next .

Příkaz Continue For okamžitě přenese řízení na další iteraci smyčky. Další informace naleznete v tématu Continue – příkaz.

Následující příklad ukazuje, jak používat Continue For příkazy a Exit For příkazy.

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

Do smyčky For Each můžete vložit libovolný počet Exit For příkazů. Při použití v rámci vnořených For Each smyček Exit For způsobí, že spuštění ukončí vnitřní smyčku a přenese řízení na další vyšší úroveň vnoření.

Exit For se často používá po vyhodnocení určité podmínky, například v If...Then...Else Struktury. Možná budete chtít použít Exit For následující podmínky:

  • Pokračování v iteraci je zbytečné nebo nemožné. Příčinou může být chybná hodnota nebo žádost o ukončení.

  • Výjimka je zachycena v Try...Catch...Finally. Můžete použít Exit For na konci Finally bloku.

  • Existuje nekonečná smyčka, což je smyčka, která by mohla spustit velký nebo dokonce nekonečný početkrát. Pokud takovou podmínku zjistíte, můžete ji použít Exit For k úniku smyčky. Další informace naleznete v tématu Do... Příkaz Loop.

Iterátory

Iterátor použijete k provedení vlastní iterace v kolekci. Iterátorem může být funkce nebo Get příslušenství. Používá příkaz Yield k vrácení každého prvku kolekce po jednom.

Iterátor můžete volat pomocí For Each...Next příkazu. Každá iterace smyčky For Each volá iterátor. Yield Při dosažení příkazu v iterátoru se vrátí výraz v Yield příkazu a aktuální umístění v kódu se zachová. Spuštění se restartuje z daného umístění při příštím volání iterátoru.

Následující příklad používá funkci iterátoru. Funkce iterátoru má Yield příkaz, který je uvnitř objektu For... Další smyčka. ListEvenNumbers V metodě každá iterace For Each těla příkazu vytvoří volání funkce iterátoru, která pokračuje k dalšímu Yield příkazu.

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

Další informace najdete v tématu Iterátory, Příkaz výnosu a Iterátor.

Technická implementace

Když ...For EachNext příkaz spustí, Visual Basic vyhodnotí kolekci pouze jednou před spuštěním smyčky. Pokud se váš blok příkazu změní element nebo grouptyto změny neovlivní iteraci smyčky.

Pokud byly všechny prvky v kolekci postupně přiřazeny element, For Each smyčka zastaví a řízení předá příkaz následující příkaz Next .

Pokud je možnost odvozena (výchozí nastavení), kompilátor jazyka Visual Basic může odvodit datový typ element. Pokud je vypnutá a element nebyla deklarována mimo smyčku, musíte ji deklarovat v For Each příkazu. Pokud chcete deklarovat datový typ element explicitně, použijte As klauzuli. Není-li datový typ prvku definován mimo For Eachkonstruktor ...Next , jeho obor je tělo smyčky. Všimněte si, že nemůžete deklarovat element vnější i vnitřní smyčku.

Volitelně můžete v Next příkazu zadatelement. To zlepšuje čitelnost programu, zejména pokud máte vnořené For Each smyčky. Musíte zadat stejnou proměnnou jako proměnnou, která se zobrazí v odpovídajícím For Each příkazu.

Možná se budete chtít vyhnout změně hodnoty element uvnitř smyčky. Díky tomu může být čtení a ladění kódu obtížnější. Změna hodnoty group nemá vliv na kolekci ani její prvky, které byly určeny při prvním zadání smyčky.

Když vnořujete smyčky, pokud Next se před vnitřní úrovní zjistí Next příkaz vnější úrovně vnoření, kompilátor signalizuje chybu. Kompilátor však může tuto překrývající se chybu rozpoznat pouze v případě, že zadáte element v každém Next příkazu.

Pokud váš kód závisí na procházení kolekce v určitém pořadí, smyčka For Each...Next není nejlepší volbou, pokud neznáte charakteristiky objektu enumerátoru, který kolekce zveřejňuje. Pořadí procházení není určeno jazykem Visual Basic, ale MoveNext metodou objektu enumerátoru. Proto možná nebudete schopni předpovědět, který prvek kolekce je první vrátit v element, nebo který je další, která se má vrátit za daný prvek. Můžete dosáhnout spolehlivějších výsledků pomocí jiné struktury smyčky, například For...Next nebo Do...Loop.

Modul runtime musí být schopen převést prvky na groupelement. Příkaz [Option Strict] určuje, zda jsou povoleny rozšiřující i zužující převody (Option Strict je vypnuto, výchozí hodnota), nebo zda jsou povoleny pouze rozšiřující převody (Option Strict je zapnuto). Další informace naleznete v tématu Zužování převodů.

Datový typ group musí být referenčním typem, který odkazuje na kolekci nebo matici, která je vyčíslitelná. Nejčastěji to znamená, že group odkazuje na objekt, který implementuje IEnumerable rozhraní System.Collections oboru názvů nebo IEnumerable<T> rozhraní System.Collections.Generic oboru názvů. System.Collections.IEnumerable definuje metodu GetEnumerator , která vrací objekt enumerátoru pro kolekci. Enumerator objekt implementuje System.Collections.IEnumerator rozhraní System.Collections oboru názvů a zveřejňuje Current vlastnost a Reset metody.MoveNext Jazyk Visual Basic je používá k procházení kolekce.

Zužující převody

Pokud Option Strict je nastavena na On, zužování převodů obvykle způsobuje chyby kompilátoru. For Each V příkazu se však převody z prvků, group které se mají element vyhodnotit a provádět za běhu, a chyby kompilátoru způsobené zúžením převodů jsou potlačeny.

V následujícím příkladu se přiřazení m jako počáteční hodnota n nekompiluje, pokud Option Strict je zapnutý, protože převod na Long hodnotu je Integer zužující převod. For Each V příkazu však není hlášena žádná chyba kompilátoru, i když přiřazení vyžaduje number stejný převod z Long .Integer For Each V příkazu, který obsahuje velké číslo, dojde k chybě za běhu při ToInteger použití na velké číslo.

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

Volání IEnumeratoru

Při spuštění For Eachsmyčky ...Next jazyka Visual Basic ověří, že group odkazuje na platný objekt kolekce. Pokud ne, vyvolá výjimku. V opačném případě volá metodu MoveNext a Current vlastnost enumerator objektu vrátit první prvek. Pokud MoveNext indikuje, že neexistuje žádný další prvek, to znamená, že pokud je kolekce prázdná, For Each smyčka zastaví a řízení předá příkaz následující příkaz Next . V opačném případě Visual Basic nastaví element první prvek a spustí blok příkazu.

Pokaždé, když Visual Basic narazí na Next příkaz, vrátí se do For Each příkazu. Znovu zavolá MoveNext a Current vrátí další prvek a znovu spustí blok nebo zastaví smyčku v závislosti na výsledku. Tento proces pokračuje, dokud MoveNext neukazuje, že neexistuje žádný další prvek nebo Exit For se zjistí příkaz.

Úprava kolekce. Objekt enumerátoru vrácený GetEnumerator normálně neumožňuje změnit kolekci přidáním, odstraněním, nahrazením nebo změnou pořadí prvků. Pokud po zahájení For Eachsmyčky ...Next změníte kolekci, objekt enumerátoru se stane neplatným a další pokus o přístup k prvku způsobí InvalidOperationException výjimku.

Toto blokování změn však není určeno jazykem Visual Basic, ale spíše implementací IEnumerable rozhraní. Je možné implementovat IEnumerable způsobem, který umožňuje úpravy během iterace. Pokud uvažujete o takové dynamické úpravě, ujistěte se, že rozumíte charakteristikám IEnumerable implementace v kolekci, kterou používáte.

Úprava prvků kolekce. Vlastnost Current enumerator objektu je ReadOnly a vrátí místní kopii každého prvku kolekce. To znamená, že nemůžete upravovat samotné prvky ve smyčce For Each...Next . Všechny provedené změny ovlivní pouze místní kopii z Current a neprojeví se zpět do podkladové kolekce. Pokud je však prvek referenčním typem, můžete upravit členy instance, na které odkazuje. Následující příklad upraví BackColor člena každého thisControl prvku. Nemůžete však změnit thisControl sám sebe.

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

Předchozí příklad může změnit BackColor člen každého thisControl prvku, i když nemůže změnit thisControl sám sebe.

Procházenípolích Vzhledem k tomu, Array že třída implementuje IEnumerable rozhraní, všechny pole zveřejňuje metodu GetEnumerator . To znamená, že můžete iterovat pole pomocí smyčky For Each...Next . Můžete ale číst pouze prvky pole. Nemůžete je změnit.

Příklad 1

Následující příklad uvádí všechny složky v adresáři C:\ pomocí DirectoryInfo třídy.

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

Příklad 2

Následující příklad znázorňuje postup řazení kolekce. Příklad seřadí instance Car třídy, které jsou uloženy v objektu List<T>. Třída Car implementuje IComparable<T> rozhraní, které vyžaduje, aby CompareTo byla metoda implementována.

Každé volání CompareTo metody vytvoří jedno porovnání, které se používá k řazení. Uživatelem napsaný kód v CompareTo metodě vrátí hodnotu pro každé porovnání aktuálního objektu s jiným objektem. Vrácená hodnota je menší než nula, pokud je aktuální objekt menší než druhý objekt, větší než nula, pokud je aktuální objekt větší než druhý objekt, a nula, pokud jsou stejné. To umožňuje definovat v kódu kritéria pro větší než, menší než a rovno.

ListCars Příkaz v cars.Sort() metodě seřadí seznam. Toto volání Sort metody způsobí, CompareTo že metoda bude volána automaticky pro Car objekty v objektu ListList<T> .

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

Viz také