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

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

Syntax

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

Součásti

Pojem Definice
element Vyžaduje se v For Each příkazu . Volitelné v Next příkazu . Proměnné. Slouží k iteraci prvky kolekce.
datatype Volitelné, pokud je on (výchozí) nebo je již deklarováno; povinné, pokud je vypnuté a Option Infer element ještě není Option Infer element deklarováno. Datový typ element .
group Povinná hodnota. Proměnná s typem, který je typu kolekce nebo Object. Odkazuje na kolekci, ve které statements se mají objekty opakovat.
statements Nepovinný parametr. Jeden nebo více příkazů mezi a For Each , které se spustí pro každou položku v Next group .
Continue For Nepovinný parametr. Přenese řízení na začátek For Each smyčky.
Exit For Nepovinný parametr. Přenese řízení mimo For Each smyčku.
Next Povinná hodnota. Ukončí definici For Each smyčky.

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 této proměnné. Při práci s kolekcí ale koncept počátečních a konečných hodnot nemá smysl a nemusíte nutně vědět, kolik prvků kolekce obsahuje. V takovém případě je často lepší volbou smyčka For Each Next ....

V následujícím příkladu For Each ...Next 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 For Each vnořit vložením jedné smyčky do druhé.

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

Při vnořování smyček musí mít každá smyčka jedinečnou element proměnnou.

Můžete také vnořit různé druhy řídicích struktur v rámci sebe navzájem. Další informace najdete v tématu Vnořené řídicí struktury.

Ukončovat a pokračovat pro

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

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

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

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 můžete umístit Exit For libovolný počet For Each příkazů. Při použití ve vnořených smyčkách způsobí spuštění ukončení nejvnitřnější smyčky a přenese řízení na další For Each Exit For vyšší úroveň vnoření.

Exit For se často používá po vyhodnocení určité podmínky, například v If ... Then ...Else Struktury. Můžete použít za Exit For následujících podmínek:

  • Nepřetržitá iterace 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 neomezený počet opakování. Pokud takovou podmínku zjistíte, můžete k řídicí Exit For smyčce použít . Další informace najdete v tématu Do... Loop – příkaz.

Iterátory

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

Iterátor zavoláte pomocí For Each...Next příkazu . Každá iterace For Each smyčky volá iterátor. Při dosažení příkazu v iterátoru je vrácen výraz v příkazu a aktuální umístění v Yield Yield kódu je zachováno. Provádění se restartuje z tohoto 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. V metodě každá iterace těla příkazu vytvoří volání funkce iterátoru, která pokračuje ListEvenNumbers For Each 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 Yield a Iterátor.

Technická implementace

Když For Each ...Next spustí příkaz , Visual Basic vyhodnocuje kolekci pouze jednou před zahájením smyčky. Pokud se blok příkazu změní nebo , tyto element group změny neovlivní iteraci smyčky.

Pokud jsou všechny prvky v kolekci následně přiřazeny k , smyčka se zastaví a řízení se předá příkazu za element For Each Next příkazem .

Pokud je option Infer on (výchozí nastavení), kompilátor Visual Basic odvodit datový typ element . Pokud je vypnutá element a není deklarována mimo smyčku, musíte ji deklarovat v For Each příkazu . K explicitní deklaraci element datového typu použijte As klauzuli . Pokud datový typ elementu není definovaný mimo For Each konstruktor ... , jeho Next oborem je tělo smyčky. Všimněte si, že nelze element deklarovat vnější i uvnitř smyčky.

Volitelně můžete v element příkazu Next zadat . Tím se zlepší čitelnost programu, zejména pokud máte vnořené For Each smyčky. Je nutné 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. To může ztížovat čtení a ladění kódu. Změna hodnoty nemá vliv na kolekci ani její prvky, které byly určeny při prvním zadání group smyčky.

Pokud při vnořování smyček dojde k příkazu vnější úrovně vnoření před vnitřní úrovní, kompilátor signalizuje Next Next chybu. Kompilátor však může tuto překrývající se chybu rozpoznat pouze v případě, že element zadáte 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 ... není nejlepší volbou, pokud nevíte charakteristiky objektu enumerátoru, který kolekce For Each Next zveřejňuje. Pořadí procházení není určeno Visual Basic, ale metodou MoveNext objektu enumerátoru. Proto možná nebudete schopni předpovědět, který prvek kolekce je první, který se vrátí v , nebo který je další prvek, který se vrátí element po daném prvku. Spolehlivějších výsledků můžete dosáhnout pomocí jiné struktury smyčky, například For ... Next nebo ... Do Loop .

Modul runtime musí být schopen převést prvky v group na element . Příkaz [ ] určuje, jestli jsou povoleny rozšiřující a zužující převody ( je vypnutá, jeho výchozí hodnota), nebo jestli jsou povolené pouze rozšiřující převody Option Strict Option Strict ( je Option Strict povoleno). Další informace najdete v tématu zužující převody.

Datový typ musí být odkazový typ, který odkazuje na kolekci nebo pole, group které je vyčíslitelné. Nejčastěji to znamená, že odkazuje na objekt, který implementuje rozhraní oboru názvů nebo group IEnumerable rozhraní oboru System.Collections IEnumerable<T> System.Collections.Generic názvů. System.Collections.IEnumerable definuje GetEnumerator metodu , která vrací objekt enumerátoru pro kolekci. Objekt enumerátor implementuje rozhraní oboru názvů a System.Collections.IEnumerator System.Collections zpřístupňuje Current vlastnost a metody a Reset MoveNext . Visual Basic je používá k přechodu do kolekce.

Zužující převody

Pokud Option Strict je nastavena On na , zužující převody obvykle způsobují chyby kompilátoru. V For Each příkazu však převod z prvků v group na element je vyhodnocován a proveden v době běhu a chyby kompilátoru způsobené zužujícími převody jsou potlačeny.

V následujícím příkladu přiřazení m jako počáteční hodnotu pro není n zkompilováno, pokud Option Strict je zapnuto, protože převod typu Long na Integer je zužující převod. V For Each příkazu však není hlášena žádná chyba kompilátoru, i když přiřazení number vyžaduje stejný převod z Long na Integer . V For Each 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í IEnumerator

při spuštění For Each smyčky... Next Visual Basic ověří, zda group odkazuje na platný objekt kolekce. V takovém případě vyvolá výjimku. V opačném případě volá MoveNext metodu a Current vlastnost objektu Enumerator pro návrat prvního prvku. Pokud MoveNext znamená, že neexistuje žádný další prvek, tedy pokud je kolekce prázdná, For Each smyčka se zastaví a ovládací prvek projde příkazem, který následuje za Next příkazem. v opačném případě Visual Basic nastaví element na první prvek a spustí blok příkazu.

pokaždé, když Visual Basic nalezne Next příkaz, vrátí se do For Each příkazu. Znovu volá MoveNext a Current vrátí další prvek a znovu buď spustí blok, nebo zastaví smyčku v závislosti na výsledku. Tento proces pokračuje MoveNext , dokud neindikuje, že není k dispozici žádný další prvek nebo Exit For 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í všech prvků. Změníte-li kolekci poté, co jste spustili For Each smyčku... Next , objekt enumerátoru se změní na neplatný a další pokus o přístup k elementu způsobí InvalidOperationException výjimku.

toto blokování úprav však není určeno Visual Basic, ale spíše implementací IEnumerable rozhraní. Je možné implementovat IEnumerable způsobem, který umožňuje úpravu během iterace. Pokud zvažujete, že provádíte tuto dynamickou úpravu, ujistěte se, že rozumíte charakteristikám IEnumerable implementace v kolekci, kterou používáte.

Úpravy prvků kolekce. CurrentVlastnost objektu Enumerator je určena jen pro čtenía vrátí místní kopii každého prvku kolekce. To znamená, že nemůžete změnit samotné prvky ve For Each smyčce.... Next Všechny změny, které provedete, ovlivní jenom místní kopii z Current a nereflektují se zpátky do příslušné kolekce. Nicméně pokud je prvek odkazový typ, můžete upravit členy instance, na kterou odkazuje. Následující příklad upravuje 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 člena každého thisControl prvku, i když nemůže thisControl sám změnit.

Procházení polí. Vzhledem k tomu Array , že třída implementuje IEnumerable rozhraní, všechna pole zpřístupňují GetEnumerator metodu. To znamená, že můžete iterovat přes pole pomocí For Each smyčky.... Next Lze však číst pouze prvky pole. Nemůžete je změnit.

Příklad 1

Následující příklad zobrazí seznam všech složek v C:. adresáře 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 pro řazení kolekce. Příklad řadí instance Car třídy, které jsou uloženy v List<T> . CarTřída implementuje IComparable<T> rozhraní, které vyžaduje CompareTo implementaci metody.

Každé volání CompareTo metody provede jedno porovnání, které se používá k řazení. Uživatelsky psaný 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.

V ListCars metodě cars.Sort() příkaz seřadí seznam. Toto volání Sort metody metody List<T> způsobí, že CompareTo Metoda bude automaticky volána pro Car objekty v 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

Viz také