針對集合中的每個項目重複一組語句。
語法
For Each element [ As datatype ] In group
[ statements ]
[ Continue For ]
[ statements ]
[ Exit For ]
[ statements ]
Next [ element ]
組件
| 術語 | 定義 |
|---|---|
element |
在 For Each 陳述句中必需的。 在語句中 Next 為選擇性。 變數。 用來逐一查看集合的專案。 |
datatype |
如果 Option Infer 為開啟或 element 已宣告,則為選擇性;如果 Option Infer 為關閉且 element 尚未宣告,則為必要專案。 的 element數據類型。 |
group |
必須的。 具有集合類型或 Object 類型的變數。 參考要重複的 statements 集合。 |
statements |
選擇性。 和之間的For EachNext一或多個語句會在中的每個group項目上執行。 |
Continue For |
選擇性。 將控制權傳輸至迴圈的 For Each 開頭。 |
Exit For |
選擇性。 將控制權移出 For Each 迴圈。 |
Next |
必須的。 結束 For Each 迴圈的定義。 |
簡單範例
For Each當您要針對集合或陣列的每個元素重複一組語句時,請使用 ...Next 迴圈。
小提示
A For...當您可以將迴圈的每個反覆專案與控件變數產生關聯,並判斷該變數的初始和最終值時,下一個語句運作良好。 不過,當您處理集合時,初始和最終值的概念並不有意義,而且您不一定知道集合具有多少個元素。 在這種情況下, For Each...Next 迴圈通常是更好的選擇。
在下列範例中 For Each,...
Next 語句會逐一查看 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
巢狀迴圈
您可以透過將一個迴圈放入另一個迴圈中來實現巢狀 For Each 迴圈。
下列範例示範巢狀 For Each...
Next 結構。
' 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
當您巢狀循環時,每個迴圈都必須有唯 element 一的變數。
您也可以將不同類型的控件結構巢狀於彼此內。 如需詳細資訊,請參閱 巢狀控件結構。
結束 For 迴圈 和 繼續 For 迴圈
Exit For 語句會導致執行結束 For...
Next 迴圈,並將控制權傳送至跟在 Next 之後的語句。
語句會 Continue For 立即將控制權傳送至迴圈的下一次迭代。 如需詳細資訊,請參閱 continue 陳述。
下列範例示範如何使用 Continue For 和 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
您可以將任意數目的 Exit For 語句放在迴圈中 For Each 。 在巢狀 For Each 迴圈內使用時, Exit For 會導致執行結束最內層的迴圈,並將控制權傳輸至下一個較高的巢狀層級。
Exit For 通常會在評估某些條件之後使用,例如,在 If...Then...Else 結構。 您可能要針對下列條件使用 Exit For :
繼續反覆運算是不必要的或不可能的。 這可能是因為錯誤值或終止要求所造成。
在 ... 中攔截到
Try例外狀況。Catch...Finally。您可以在區塊結尾Finally使用Exit For。有無止盡的迴圈,這是一個迴圈,可以執行大量甚至無限次數。 如果您偵測到這類條件,您可以使用
Exit For來逸出迴圈。 如需詳細資訊,請參閱 Do...迴圈陳述句。
迭代器
您可以使用 反覆運算器 在集合上執行自訂反覆專案。 反覆運算器可以是函式或 Get 存取子。 它會使用 Yield 語句一次傳回集合的每個專案。
您可以使用語句來呼叫反覆運算器 For Each...Next 。 每次迴圈 For Each 的迴圈執行都會呼叫迭代器。
Yield在反覆運算器中到達 語句時,會傳回 語句中的Yield表達式,並保留程序代碼中的目前位置。 下次呼叫反覆運算器時,會從該位置重新啟動執行。
下列範例使用反覆運算器函式。 反覆運算器函式具有 YieldFor... 內的 語句下一個 迴圈。 在方法中 ListEvenNumbers ,語句主體的每個反覆 For Each 項目都會建立反覆運算器函式的呼叫,該函式會繼續進行下一個 Yield 語句。
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
如需詳細資訊,請參閱 反覆運算器、 Yield 語句和 反覆運算器。
技術實作
當 ...For Each
Next 語句執行時,Visual Basic 只會評估集合一次,然後迴圈才會開始。 如果您的語句封鎖變更 element 或 group,這些變更不會影響迴圈的反覆專案。
當集合中的所有專案都已連續指派給 element時, For Each 迴圈會停止和控制傳遞至 語句之後的 Next 語句。
如果 Option Infer 開啟 (其預設設定),則 Visual Basic 編譯程式可以推斷 的 element數據類型。 如果它已關閉且 element 尚未在迴圈外部宣告,您必須在 語句中 For Each 宣告它。 若要明確宣告的 element 數據類型,請使用 As 子句。 除非元素的數據類型定義在 For Each...Next 建構之外,否則其範圍是循環的主體。 請注意,您無法在 循環內外宣告 element 。
您可以選擇性地在 Next 語句中指定 element 。 這可改善程式的可讀性,特別是如果您有巢狀 For Each 迴圈。 您必須指定與對應 For Each 語句中顯示的變數相同。
您可能想要避免在循環內變更 的值 element 。 這樣做可讓讀取和偵錯您的程式代碼更加困難。 變更 的值 group 不會影響集合或其元素,這是在第一次輸入迴圈時決定的。
當您是巢狀循環時,如果在 Next 內部層級的 之前 Next 遇到外部巢狀層級的語句,則編譯程式會發出錯誤訊號。 不過,只有在您在每個element語句中指定Next時,編譯程式才能偵測到這個重疊的錯誤。
如果您的程式代碼相依於以特定順序周遊集合, For Each除非您知道集合所公開的列舉值物件特性,否則 ...Next 迴圈不是最佳選擇。 周遊的順序不是由Visual Basic決定,而是由 MoveNext 列舉值物件的方法決定。 因此,您可能無法預測集合中第一個傳回 element的專案,或是在指定項目之後傳回的下一個專案。 您可以使用不同的循環結構來達成更可靠的結果,例如 For...Next 或 Do...Loop。
執行時間必須將 中的groupelement項目轉換成 。 [Option Strict] 語句會控制是否允許擴大和縮小轉換(Option Strict 關閉、其預設值),或是否只允許擴大轉換(Option Strict 開啟)。 如需詳細資訊,請參閱 縮小轉換範圍。
的數據類型 group 必須是參考型別,參考集合或可列舉的陣列。 最常見的是,這group表示是指IEnumerable實作命名空間介面或IEnumerable<T>命名空間介面System.Collections的物件System.Collections.Generic。
System.Collections.IEnumerable 定義 GetEnumerator 方法,這個方法會傳回集合的列舉值物件。 列舉值物件會實作 System.Collections.IEnumerator 命名空間的 System.Collections 介面,並公開 Current 屬性和 和 ResetMoveNext 方法。 Visual Basic 會使用這些來周遊集合。
縮小轉換
當 設定為 On時Option Strict,縮小轉換通常會造成編譯程序錯誤。
For Each不過,在語句中,中的項目groupelement轉換會在運行時間進行評估和執行,並隱藏因縮小轉換所造成的編譯程序錯誤。
在下列範例中,當 開啟 時Option Strict,做為 初始值的n指派m不會編譯,因為 轉換成 LongInteger 的是縮小轉換。 不過,在語句中 For Each ,不會報告編譯程式錯誤,即使 的指派 number 需要從 Long 相同的轉換至 Integer。
For Each在包含大量數目的 語句中,當套用至大量時ToInteger,就會發生運行時錯誤。
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
IEnumerator 呼叫
For Each執行 ...Next 迴圈時,Visual Basic 會驗證參考group有效的集合物件。 如果沒有,則會擲回例外狀況。 否則,它會呼叫 MoveNext 列舉值物件的 方法和 Current 屬性,以傳回第一個專案。 如果 MoveNext 表示沒有下一個項目,也就是說,如果集合是空的, For Each 迴圈會停止和控制傳遞至 語句之後的 Next 語句。 否則,Visual Basic 會將 設定 element 為第一個專案,並執行語句區塊。
每次 Visual Basic 遇到 Next 語句時,都會傳 For Each 回 語句。 同樣地,它會呼叫 MoveNext 並 Current 傳回下一個專案,然後再次執行 區塊或根據結果停止迴圈。 此程式會繼續執行,直到 MoveNext 指出沒有下一個專案 Exit For 或遇到 語句為止。
修改集合。 通常傳回的 GetEnumerator 列舉值物件不會讓您藉由新增、刪除、取代或重新排序任何元素來變更集合。 如果您在起始 For Each...Next 循環之後變更集合,列舉值物件就會變成無效,而下一次嘗試存取專案會造成 InvalidOperationException 例外狀況。
不過,這項修改封鎖不是由Visual Basic決定,而是由介面的實作 IEnumerable 決定。 您可以透過 IEnumerable 允許在反覆項目期間修改的方式實作。 如果您考慮進行這類動態修改,請確定您已瞭解所使用集合上實作 IEnumerable 的特性。
修改集合專案。
Current列舉值對象的 屬性是 ReadOnly,它會傳回每個集合專案的本機複本。 這表示您無法在 ...Next 迴圈中For Each修改專案本身。 您所做的任何修改只會影響本機 Current 複本,而且不會反映回基礎集合中。 不過,如果專案是參考型別,您可以修改它所指向之實例的成員。 下列範例會 BackColor 修改每個 thisControl 元素的成員。 不過,您無法自行修改 thisControl 。
Sub LightBlueBackground(thisForm As System.Windows.Forms.Form)
For Each thisControl In thisForm.Controls
thisControl.BackColor = System.Drawing.Color.LightBlue
Next thisControl
End Sub
上一個範例可以修改 BackColor 每個 thisControl 元素的成員,但無法修改 thisControl 本身。
周遊陣列。
Array因為類別會實作 IEnumerable 介面,因此所有數位都會公開 GetEnumerator 方法。 這表示您可以使用 ...Next 迴圈逐一查看陣列For Each。 不過,您只能讀取陣列元素。 您無法變更它們。
範例 1
下列範例會使用 DirectoryInfo 類別列出 C:\ 目錄中的所有資料夾。
Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
Debug.WriteLine(dir.Name)
Next
範例 2
下列範例說明排序集合的程式。 此範例會排序儲存在中的List<T>類別實例Car。 類別 Car 實作了 IComparable<T> 介面,因此需要實作 CompareTo 方法。
方法的每個呼叫 CompareTo 都會進行用於排序的單一比較。 方法中 CompareTo 使用者撰寫的程式代碼會針對目前物件與另一個物件的每個比較傳回值。 如果目前物件小於其他物件,則傳回的值小於零,如果目前物件大於其他物件,則大於零;如果物件相等則為零。 這可讓您在程式代碼中定義大於、小於和等於的準則。
在ListCars方法中,cars.Sort()語句用來排序列表。 這個對 Sort 方法的 List<T> 呼叫會自動調用 CompareTo 方法,該方法將針對 Car 中的 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