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žítExit Forna konciFinallybloku.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 Forsmyč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