Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Powtarza grupę instrukcji dla każdego elementu w kolekcji.
Składnia
For Each element [ As datatype ] In group
[ statements ]
[ Continue For ]
[ statements ]
[ Exit For ]
[ statements ]
Next [ element ]
Części
| Termin | Definicja |
|---|---|
element |
Wymagane w instrukcji For Each . Opcjonalnie w instrukcji Next . Zmienna. Służy do iterowania elementów kolekcji. |
datatype |
Opcjonalnie, jeśli Option Infer wartość jest włączona (wartość domyślna) lub element jest już zadeklarowana; wymagana, jeśli Option Infer jest wyłączona i element nie jest jeszcze zadeklarowana. Typ danych .element |
group |
To jest wymagane. Zmienna o typie kolekcji lub obiekcie. Odnosi się do kolekcji, w której statements mają być powtarzane. |
statements |
Opcjonalny. Co najmniej jedna instrukcja między For EachNext i uruchamiana na każdym elemencie w elemencie group. |
Continue For |
Opcjonalny. Przenosi kontrolkę na początek For Each pętli. |
Exit For |
Opcjonalny. Przenosi kontrolkę poza pętlę For Each . |
Next |
To jest wymagane. Przerywa definicję For Each pętli. |
Prosty przykład
For EachUżyj pętli ...Next, jeśli chcesz powtórzyć zestaw instrukcji dla każdego elementu kolekcji lub tablicy.
Wskazówka
A dla... Następna instrukcja sprawdza się dobrze, gdy można skojarzyć każdą iterację pętli ze zmienną kontrolną i określić początkowe i końcowe wartości tej zmiennej. Jednak jeśli masz do czynienia z kolekcją, koncepcja początkowych i końcowych wartości nie jest znacząca i nie musisz wiedzieć, ile elementów ma kolekcja. W takim przypadku pętla For Each...Next jest często lepszym wyborem.
W poniższym przykładzie ...For Each
Next instrukcja iteruje wszystkie elementy kolekcji 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
Aby uzyskać więcej przykładów, zobacz Kolekcje i tablice.
Pętle zagnieżdżone
Pętle For Each można zagnieżdżać, wstawiając jedną pętlę w drugą.
W poniższym przykładzie pokazano zagnieżdżone For Each...
Next Struktur.
' 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
W przypadku zagnieżdżania pętli każda pętla musi mieć unikatową element zmienną.
Można również zagnieżdżać różne rodzaje struktur sterujących w sobie. Aby uzyskać więcej informacji, zobacz Zagnieżdżone struktury sterujące.
Przerwij dla i kontynuuj dla
Instrukcja Exit For powoduje zakończenie Forwykonywania ...
Next pętla przekazuje sterowanie do instrukcji następującej po instrukcji Next.
Instrukcja Continue For przenosi kontrolkę natychmiast do następnej iteracji pętli. Aby uzyskać więcej informacji, zobacz Instrukcja kontynuacji.
W poniższym przykładzie pokazano, jak używać instrukcji Continue For and Exit For .
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
W pętli można umieścić dowolną For Each liczbę instrukcjiExit For. W przypadku użycia w pętlach Exit For zagnieżdżonych For Each wykonywanie powoduje wyjście z pętli najdalej wewnętrznej i transferuje kontrolkę do następnego wyższego poziomu zagnieżdżania.
Exit For jest często używany po ocenie jakiegoś warunku, na przykład w If...Then...Else struktura. Możesz chcieć użyć Exit For w przypadku następujących sytuacji:
Kontynuowanie iteracji jest niepotrzebne lub niemożliwe. Może to być spowodowane błędną wartością lub żądaniem zakończenia.
Wyjątek jest przechwycony w ...
TryCatch...Finally. Możesz użyćExit Forna końcuFinallybloku.Istnieje nieskończona pętla, która jest pętlą, która może uruchamiać dużą lub nawet nieskończoną liczbę razy. Jeśli wykryjesz taki warunek, możesz użyć
Exit Fordo przerwania pętli. Aby uzyskać więcej informacji, zobacz Instrukcja Do...Loop.
Iteratory
Iterator służy do wykonywania niestandardowej iteracji w kolekcji. Iterator może być funkcją lub akcesorem Get . Używa instrukcji Yield , aby zwrócić każdy element kolekcji pojedynczo.
Iterator jest wywoływany przy użyciu instrukcji For Each...Next . Każda iteracja For Each pętli wywołuje iterator.
Yield Po osiągnięciu instrukcji w iteratorze Yield wyrażenie w instrukcji jest zwracane, a bieżąca lokalizacja w kodzie jest zachowywana. Wykonanie jest uruchamiane ponownie z tej lokalizacji przy następnym wywołaniu iteratora.
W poniższym przykładzie użyto funkcji iteratora. Funkcja iteratora ma instrukcję Yield wewnątrz elementu For... Następna pętla. W metodzie ListEvenNumbers każda iteracja For Each treści instrukcji tworzy wywołanie funkcji iteratora, która przechodzi do następnej Yield instrukcji.
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
Aby uzyskać więcej informacji, zobacz Iteratory, Yield Statement i Iterator.
Implementacja techniczna
Gdy ...For Each
Next instrukcja jest uruchamiana, program Visual Basic ocenia kolekcję tylko raz, zanim rozpocznie się pętla. Jeśli blok instrukcji zmieni się element lub group, te zmiany nie mają wpływu na iterację pętli.
Gdy wszystkie elementy w kolekcji zostały kolejno przypisane do elementelementu , pętla For Each zatrzymuje się i kontrolka przechodzi do instrukcji po instrukcji Next .
Jeśli wywnioskowanie opcji jest włączone (ustawienie domyślne), kompilator języka Visual Basic może wywnioskować typ elementdanych . Jeśli jest wyłączona i element nie została zadeklarowana poza pętlą, musisz zadeklarować ją w instrukcji For Each . Aby zadeklarować typ element danych jawnie, użyj klauzuli As . Chyba że typ danych elementu jest zdefiniowany poza konstrukcją For Each...Next , jego zakres jest treścią pętli. Należy pamiętać, że nie można zadeklarować element zarówno zewnętrznej, jak i wewnątrz pętli.
Opcjonalnie można określić element w instrukcji Next . Poprawia to czytelność programu, zwłaszcza jeśli masz zagnieżdżone For Each pętle. Musisz określić tę samą zmienną co zmienną wyświetlaną w odpowiedniej For Each instrukcji.
Możesz uniknąć zmiany wartości element wewnątrz pętli. Może to utrudnić odczytywanie i debugowanie kodu. Zmiana wartości group elementu nie ma wpływu na kolekcję ani jej elementy, które zostały określone podczas pierwszego wprowadzenia pętli.
W przypadku zagnieżdżania pętli, jeśli Next wystąpi instrukcja poziomu zagnieżdżania zewnętrznego przed Next poziomem wewnętrznym, kompilator sygnalizuje błąd. Jednak kompilator może wykryć ten nakładający się błąd tylko wtedy, gdy określisz element w każdej Next instrukcji.
Jeśli kod zależy od przechodzenia kolekcji w określonej kolejności, For Eachpętla ...Next nie jest najlepszym wyborem, chyba że znasz cechy obiektu wyliczającego, które uwidacznia kolekcja. Kolejność przechodzenia nie jest określana przez język Visual Basic, ale przez MoveNext metodę obiektu wyliczającego. W związku z tym może nie być w stanie przewidzieć, który element kolekcji jest pierwszym elementem, który ma zostać zwrócony w elementelemecie , lub który jest następny, który ma zostać zwrócony po danym elemecie. Możesz osiągnąć bardziej niezawodne wyniki przy użyciu innej struktury pętli, takiej jak For...Next lub Do...Loop.
Środowisko uruchomieniowe musi mieć możliwość przekonwertowania elementów w group pliku na element. Instrukcja [Option Strict] określa, czy dozwolone są konwersje rozszerzające i zawężające (Option Strict jest wyłączone, jego wartość domyślna) lub czy dozwolone są tylko konwersje rozszerzające (Option Strict jest włączone). Aby uzyskać więcej informacji, zobacz Zawężanie konwersji.
Typ group danych musi być typem odwołania odwołującym się do kolekcji lub tablicy, która jest wyliczana. Najczęściej oznacza to, że group odnosi się do obiektu, który implementuje IEnumerable interfejs System.Collections przestrzeni nazw lub IEnumerable<T> interfejs System.Collections.Generic przestrzeni nazw.
System.Collections.IEnumerable definiuje metodę GetEnumerator , która zwraca obiekt modułu wyliczającego dla kolekcji. Obiekt modułu wyliczającego implementuje System.Collections.IEnumerator interfejs System.Collections przestrzeni nazw i uwidacznia Current właściwość oraz Reset metody i MoveNext . Program Visual Basic używa tych elementów do przechodzenia przez kolekcję.
Zawężanie konwersji
Gdy Option Strict jest ustawiona wartość On, konwersje zawężające zwykle powodują błędy kompilatora.
For Each Jednak w instrukcji konwersje z elementów w group programie do element są oceniane i wykonywane w czasie wykonywania, a błędy kompilatora spowodowane zawężeniem konwersji są pomijane.
W poniższym przykładzie przypisanie m wartości jako początkowej wartości n nie jest kompilowane, gdy Option Strict jest włączone, ponieważ konwersja Long elementu na element Integer jest konwersją zawężającą. Jednak w instrukcji For Each nie jest zgłaszany żaden błąd kompilatora, mimo że przypisanie number wymaga tej samej konwersji z Long na Integer. W instrukcji For Each zawierającej dużą liczbę występuje błąd czasu wykonywania, gdy ToInteger jest stosowany do dużej liczby.
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
Wywołania modułu IEnumerator
Po uruchomieniu For Eachpętli ...Next program Visual Basic sprawdza, czy group odwołuje się do prawidłowego obiektu kolekcji. Jeśli nie, zgłasza wyjątek. W przeciwnym razie wywołuje metodę MoveNext i Current właściwość obiektu modułu wyliczającego, aby zwrócić pierwszy element. Jeśli MoveNext wskazuje, że nie ma następnego elementu, oznacza to, że jeśli kolekcja jest pusta, For Each pętla zatrzymuje się i kontrolka przechodzi do instrukcji następującej po instrukcji Next . W przeciwnym razie program Visual Basic ustawia element element na pierwszy element i uruchamia blok instrukcji.
Za każdym razem, gdy program Visual Basic napotka instrukcję Next , powraca do instrukcji For Each . Ponownie wywołuje MoveNext i Current zwraca następny element, a następnie ponownie uruchamia blok lub zatrzymuje pętlę w zależności od wyniku. Ten proces będzie kontynuowany, dopóki MoveNext nie zostanie wyświetlony żaden następny element lub Exit For instrukcja nie zostanie napotkana.
Modyfikowanie kolekcji. Obiekt modułu wyliczającego zwracany przez GetEnumerator zwykle nie pozwala na zmianę kolekcji przez dodanie, usunięcie, zastąpienie lub zmianę kolejności wszystkich elementów. Jeśli zmienisz kolekcję po zainicjowaniu For Eachpętli ...Next , obiekt modułu wyliczającego stanie się nieprawidłowy, a następna próba uzyskania dostępu do elementu powoduje InvalidOperationException wyjątek.
Jednak to blokowanie modyfikacji nie jest określane przez visual basic, ale raczej przez implementację interfejsu IEnumerable . Istnieje możliwość zaimplementowania IEnumerable w sposób umożliwiający modyfikację podczas iteracji. Jeśli rozważasz taką dynamiczną modyfikację, upewnij się, że rozumiesz cechy IEnumerable implementacji używanej kolekcji.
Modyfikowanie elementów kolekcji. Właściwość Current obiektu modułu wyliczającego to ReadOnly i zwraca lokalną kopię każdego elementu kolekcji. Oznacza to, że nie można modyfikować samych elementów w For Eachpętli ...Next . Wszelkie wprowadzone modyfikacje mają wpływ tylko na lokalną kopię z Current i nie są odzwierciedlane z powrotem do bazowej kolekcji. Jeśli jednak element jest typem odwołania, można zmodyfikować elementy członkowskie wystąpienia, do którego wskazuje. Poniższy przykład modyfikuje BackColor element członkowski każdego thisControl elementu. Nie można jednak zmodyfikować thisControl samego siebie.
Sub LightBlueBackground(thisForm As System.Windows.Forms.Form)
For Each thisControl In thisForm.Controls
thisControl.BackColor = System.Drawing.Color.LightBlue
Next thisControl
End Sub
Poprzedni przykład może modyfikować BackColor składowe każdego thisControl elementu, chociaż nie może modyfikować thisControl się.
Przechodzenie tablic.
Array Ponieważ klasa implementuje IEnumerable interfejs, wszystkie tablice uwidaczniają metodę GetEnumerator . Oznacza to, że można iterować przez tablicę za pomocą For Eachpętli ...Next . Można jednak odczytywać tylko elementy tablicy. Nie można ich zmienić.
Przykład 1
W poniższym przykładzie wymieniono wszystkie foldery w katalogu C:\ przy użyciu DirectoryInfo klasy .
Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
Debug.WriteLine(dir.Name)
Next
Przykład 2
Poniższy przykład ilustruje procedurę sortowania kolekcji. Przykład sortuje wystąpienia Car klasy przechowywanej w obiekcie List<T>. Klasa Car implementuje interfejs IComparable<T>, który wymaga zaimplementowania metody CompareTo.
Każde wywołanie CompareTo metody sprawia, że pojedyncze porównanie jest używane do sortowania. Kod napisany przez użytkownika w metodzie CompareTo zwraca wartość dla każdego porównania bieżącego obiektu z innym obiektem. Zwrócona wartość jest mniejsza niż zero, jeśli bieżący obiekt jest mniejszy niż inny obiekt, większy niż zero, jeśli bieżący obiekt jest większy niż inny obiekt i zero, jeśli są równe. Dzięki temu można zdefiniować w kodzie kryteria bycia większym niż, mniejszym niż i równym.
W metodzie ListCars instrukcja cars.Sort() sortuje listę. Wywołanie metody Sort w List<T> powoduje, że metoda CompareTo jest wywoływana automatycznie dla obiektów Car w 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