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 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 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žítExit For
na konciFinally
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 Each
Next
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 group
tyto 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 Each
konstruktor ...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 group
element
. 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 Each
smyč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 Each
smyč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 List
List<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