For Each...Next 陳述式 (Visual Basic)For Each...Next Statement (Visual Basic)

針對集合中的每個元素重複一組語句。Repeats a group of statements for each element in a collection.

語法Syntax

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

組件Parts

詞彙Term 定義Definition
element For Each 語句中為必要項。Required in the For Each statement. Next 語句中為選擇性。Optional in the Next statement. 變.Variable. 用來逐一查看集合的元素。Used to iterate through the elements of the collection.
datatype 如果Option Infer是 on (預設值)或 element 已宣告,則為選擇性;如果 Option Infer 已關閉,而且 element 尚未宣告,則為必要。Optional if Option Infer is on (the default) or element is already declared; required if Option Infer is off and element isn't already declared. element的資料型別。The data type of element.
group 必要項。Required. 類型為的變數,其為集合類型或物件。A variable with a type that's a collection type or Object. 表示要重複 @no__t 0 的集合。Refers to the collection over which the statements are to be repeated.
statements 選擇性。Optional. group 中的每個專案上執行的 For EachNext 之間的一個或多個語句。One or more statements between For Each and Next that run on each item in group.
Continue For 選擇性。Optional. 將控制權轉移至 For Each 迴圈的開頭。Transfers control to the start of the For Each loop.
Exit For 選擇性。Optional. 將控制權從 For Each 迴圈轉移出去。Transfers control out of the For Each loop.
Next 必要項。Required. 終止 For Each 迴圈的定義。Terminates the definition of the For Each loop.

簡單範例Simple Example

當您想要針對集合或陣列的每個元素重複一組語句時,請使用 For Each ... @no__t 1 迴圈。Use a For Each...Next loop when you want to repeat a set of statements for each element of a collection or array.

提示

適用于 。當您可以將迴圈的每個反復專案與控制項變數產生關聯,並判斷該變數的初始值和最後一個值時,下一個語句就很好用。A For...Next Statement works well when you can associate each iteration of a loop with a control variable and determine that variable's initial and final values. 不過,當您處理集合時,初始和最終值的概念並沒有意義,而且您不一定知道集合具有多少元素。However, when you are dealing with a collection, the concept of initial and final values isn't meaningful, and you don't necessarily know how many elements the collection has. 在這種情況下,For Each ... @no__t 1 迴圈通常是較佳的選擇。In this kind of case, a For Each...Next loop is often a better choice.

在下列範例中,For Each ... NextIn the following example, the For EachNext 語句會逐一查看清單集合的所有元素。statement iterates through all the elements of a List collection.

' 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 more examples, see Collections and Arrays.

嵌套迴圈Nested Loops

您可以藉由將一個迴圈放在另一個迴圈中,來將 For Each 個迴圈。You can nest For Each loops by putting one loop within another.

下列範例示範 nested For Each ... NextThe following example demonstrates nested For EachNext 構造.structures.

' 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 

當您嵌套迴圈時,每個迴圈都必須有唯一的 @no__t 0 變數。When you nest loops, each loop must have a unique element variable.

您也可以在彼此之間嵌套不同類型的控制結構。You can also nest different kinds of control structures within each other. 如需詳細資訊,請參閱嵌套控制項結構For more information, see Nested Control Structures.

結束並繼續進行Exit For and Continue For

Exit For語句會導致執行結束 For ... NextThe Exit For statement causes execution to exit the ForNext 迴圈,並將控制權轉移至 Next 語句後面的語句。loop and transfers control to the statement that follows the Next statement.

@No__t 0 語句會立即將控制權轉移到迴圈的下一個反復專案。The Continue For statement transfers control immediately to the next iteration of the loop. 如需詳細資訊,請參閱Continue 語句For more information, see Continue Statement.

下列範例顯示如何使用 Continue ForExit For 語句。The following example shows how to use the Continue For and Exit For statements.

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 7, 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 語句放在 @no__t 1 迴圈中。You can put any number of Exit For statements in a For Each loop. 在 nested For Each 迴圈中使用時,Exit For 會使執行結束最內層的迴圈,並將控制權轉移至下一個較高層級的嵌套。When used within nested For Each loops, Exit For causes execution to exit the innermost loop and transfers control to the next higher level of nesting.

Exit For 通常會在評估某些條件之後使用,例如,在 If ... Then ... Else 結構中。Exit For is often used after an evaluation of some condition, for example, in an If...Then...Else structure. 在下列情況中,您可能會想要使用 Exit ForYou might want to use Exit For for the following conditions:

  • 繼續進行反覆運算是不必要或不可能的。Continuing to iterate is unnecessary or impossible. 這可能是由錯誤值或終止要求所造成。This might be caused by an erroneous value or a termination request.

  • @No__t-0 ... Catch ... Finally 中攔截到例外狀況。您可以使用 Finally 區塊結尾的 Exit ForAn exception is caught in a Try...Catch...Finally. You might use Exit For at the end of the Finally block.

  • 有一個無止盡的迴圈,這是一種迴圈,可能會執行很長或甚至無限次的次數。There an endless loop, which is a loop that could run a large or even infinite number of times. 如果您偵測到這種情況,您可以使用 Exit For 來取消迴圈。If you detect such a condition, you can use Exit For to escape the loop. 如需詳細資訊,請參閱Do 。Loop 語句For more information, see Do...Loop Statement.

迭代器Iterators

您可以使用反覆運算器,在集合上執行自訂反復專案。You use an iterator to perform a custom iteration over a collection. Iterator 可以是函數或 @no__t 0 的存取子。An iterator can be a function or a Get accessor. 它會使用 Yield 語句,一次傳回一個集合的每個專案。It uses a Yield statement to return each element of the collection one at a time.

您可以使用 For Each...Next 語句來呼叫反覆運算器。You call an iterator by using a For Each...Next statement. For Each 迴圈的每個反覆項目都會呼叫迭代器。Each iteration of the For Each loop calls the iterator. 當反覆運算器中到達 @no__t 0 的語句時,會傳回 Yield 語句中的運算式,並保留程式碼中的目前位置。When a Yield statement is reached in the iterator, the expression in the Yield statement is returned, and the current location in code is retained. 下一次呼叫迭代器時,便會從這個位置重新開始執行。Execution is restarted from that location the next time that the iterator is called.

下列範例會使用 iterator 函數。The following example uses an iterator function. Iterator 函數的 Yield 語句位於For 。下一個迴圈。The iterator function has a Yield statement that's inside a For…Next loop. ListEvenNumbers 方法中,@no__t 1 語句主體的每個反復專案都會建立對 iterator 函式的呼叫,該函數會繼續進行下一個 Yield 語句。In the ListEvenNumbers method, each iteration of the For Each statement body creates a call to the iterator function, which proceeds to the next Yield statement.

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 語句IteratorFor more information, see Iterators, Yield Statement, and Iterator.

技術實作Technical Implementation

For Each ... NextWhen a For EachNext 語句會執行,Visual Basic 在迴圈開始之前,只會評估集合一次。statement runs, Visual Basic evaluates the collection only one time, before the loop starts. 如果您的語句區塊 elementgroup 變更,這些變更不會影響迴圈的反復專案。If your statement block changes element or group, these changes don't affect the iteration of the loop.

當集合中的所有元素連續指派給 element 時,@no__t 1 迴圈就會停止,並將控制權傳遞至 Next 語句之後的語句。When all the elements in the collection have been successively assigned to element, the For Each loop stops and control passes to the statement following the Next statement.

如果Option 推斷為 on (其預設設定),則 Visual Basic 編譯器可以推斷 element 的資料類型。If Option Infer is on (its default setting), the Visual Basic compiler can infer the data type of element. 如果已關閉,而且 element 尚未在迴圈外宣告,您就必須在 For Each 語句中宣告它。If it is off and element hasn't been declared outside the loop, you must declare it in the For Each statement. 若要明確宣告 element 的資料類型,請使用 As 子句。To declare the data type of element explicitly, use an As clause. 除非元素的資料類型是在 For Each ... Next 結構之外定義,否則其範圍就是迴圈的主體。Unless the data type of element is defined outside the For Each...Next construct, its scope is the body of the loop. 請注意,您無法在迴圈的外部和內部宣告 elementNote that you cannot declare element both outside and inside the loop.

您可以選擇性地在 Next 語句中指定 elementYou can optionally specify element in the Next statement. 這可以改善程式的可讀性,特別是當您有嵌套的 For Each 迴圈時。This improves the readability of your program, especially if you have nested For Each loops. 您必須指定與對應的 For Each 語句中出現的相同變數。You must specify the same variable as the one that appears in the corresponding For Each statement.

您可能想要避免在迴圈內變更 element 的值。You might want to avoid changing the value of element inside a loop. 這麼做可能會讓您更難以讀取和偵錯工具代碼。Doing this can make it more difficult to read and debug your code. 變更 group 的值並不會影響集合或其元素,這是在第一次進入迴圈時決定的。Changing the value of group doesn't affect the collection or its elements, which were determined when the loop was first entered.

當您要建立迴圈時,如果內部層級的 Next 之前遇到外部嵌套層級的 Next 語句,則編譯器會發出錯誤信號。When you're nesting loops, if a Next statement of an outer nesting level is encountered before the Next of an inner level, the compiler signals an error. 不過,只有當您在每個 Next 語句中指定 element 時,編譯器才會偵測到這個重迭的錯誤。However, the compiler can detect this overlapping error only if you specify element in every Next statement.

如果您的程式碼相依于依特定順序來進行集合,除非您知道集合所公開之列舉值物件的特性,否則 For Each ... Next 迴圈不是最佳選擇。If your code depends on traversing a collection in a particular order, a For Each...Next loop isn't the best choice, unless you know the characteristics of the enumerator object the collection exposes. 定序的順序不是由 Visual Basic,而是由列舉值物件的 MoveNext 方法所決定。The order of traversal isn't determined by Visual Basic, but by the MoveNext method of the enumerator object. 因此,您可能無法預測集合的哪個元素是第一個要傳回的專案 element,或在指定的專案之後要傳回的下一個專案。Therefore, you might not be able to predict which element of the collection is the first to be returned in element, or which is the next to be returned after a given element. 您可以使用不同的迴圈結構(例如 For ... NextDo ... Loop)來達到更可靠的結果。You might achieve more reliable results using a different loop structure, such as For...Next or Do...Loop.

執行時間必須能夠將 group 中的元素轉換成 elementThe runtime must be able to convert the elements in group to element. [@No__t-0] 語句控制是否允許擴展和縮小轉換(Option Strict 已關閉、其預設值),或只允許擴輾轉換(Option Strict 是 on)。The [Option Strict] statement controls whether both widening and narrowing conversions are allowed (Option Strict is off, its default value), or whether only widening conversions are allowed (Option Strict is on). 如需詳細資訊,請參閱縮小轉換For more information, see Narrowing conversions.

@No__t-0 的資料類型必須是參考類型,或可列舉的陣列。The data type of group must be a reference type that refers to a collection or an array that's enumerable. 最常見的意思是,group 指的是一個物件,它會執行 System.Collections 命名空間的 @no__t 1 介面,或 System.Collections.Generic 命名空間的 @no__t 3 介面。Most commonly this means that group refers to an object that implements the IEnumerable interface of the System.Collections namespace or the IEnumerable<T> interface of the System.Collections.Generic namespace. System.Collections.IEnumerable 會定義 GetEnumerator 方法,這會傳回集合的列舉值物件。System.Collections.IEnumerable defines the GetEnumerator method, which returns an enumerator object for the collection. 列舉值物件會執行 @no__t 1 命名空間的 @no__t 0 介面,並公開 Current 屬性和 Reset 和 @no__t 4 方法。The enumerator object implements the System.Collections.IEnumerator interface of the System.Collections namespace and exposes the Current property and the Reset and MoveNext methods. Visual Basic 會使用這些來遍歷集合。Visual Basic uses these to traverse the collection.

縮小轉換Narrowing Conversions

Option Strict 設定為 On 時,縮小轉換通常會造成編譯器錯誤。When Option Strict is set to On, narrowing conversions ordinarily cause compiler errors. 不過,在 @no__t 0 的語句中,從 group 的專案轉換為 element 會在執行時間進行評估和執行,而且會隱藏縮小轉換所造成的編譯器錯誤。In a For Each statement, however, conversions from the elements in group to element are evaluated and performed at run time, and compiler errors caused by narrowing conversions are suppressed.

在下列範例中,當 Option Strict 為 on 時,m 的指派 n 的初始值不會進行編譯,因為 Long 轉換成 Integer 是縮小轉換。In the following example, the assignment of m as the initial value for n doesn't compile when Option Strict is on because the conversion of a Long to an Integer is a narrowing conversion. 不過,在 For Each 語句中,不會報告任何編譯器錯誤,即使指派給 number 也需要從 LongInteger 的相同轉換。In the For Each statement, however, no compiler error is reported, even though the assignment to number requires the same conversion from Long to Integer. 在包含大量數位的 For Each 語句中,當 ToInteger 套用至大數位時,就會發生執行階段錯誤。In the For Each statement that contains a large number, a run-time error occurs when ToInteger is applied to the large number.

Option Strict On

Module Module1
    Sub Main()
        ' 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

        Console.ReadKey()
    End Sub
End Module

IEnumerator 呼叫IEnumerator Calls

For Each ... Next 迴圈開始執行時,Visual Basic 會確認 group 是指有效的集合物件。When execution of a For Each...Next loop starts, Visual Basic verifies that group refers to a valid collection object. 如果沒有,則會擲回例外狀況。If not, it throws an exception. 否則,它會呼叫 MoveNext 方法和列舉值物件的 @no__t 1 屬性,以傳回第一個元素。Otherwise, it calls the MoveNext method and the Current property of the enumerator object to return the first element. 如果 MoveNext 指出沒有下一個專案,也就是,如果集合是空的,則 @no__t 1 迴圈會停止,並將控制權傳遞至 Next 語句之後的語句。If MoveNext indicates that there is no next element, that is, if the collection is empty, the For Each loop stops and control passes to the statement following the Next statement. 否則,Visual Basic 會將 element 設定為第一個元素,並執行語句區塊。Otherwise, Visual Basic sets element to the first element and runs the statement block.

每次 Visual Basic 遇到 @no__t 0 的語句時,它會回到 For Each 語句。Each time Visual Basic encounters the Next statement, it returns to the For Each statement. 同樣地,它會呼叫 MoveNext,並 Current 傳回下一個專案,然後再執行區塊或停止迴圈,視結果而定。Again it calls MoveNext and Current to return the next element, and again it either runs the block or stops the loop depending on the result. 此程式會繼續進行,直到 MoveNext 指出沒有下一個元素,或遇到 @no__t 1 的語句為止。This process continues until MoveNext indicates that there is no next element or an Exit For statement is encountered.

修改集合。Modifying the Collection. @No__t-0 所傳回的列舉值物件,通常不會讓您藉由新增、刪除、取代或重新排列任何元素來變更集合。The enumerator object returned by GetEnumerator normally doesn't let you change the collection by adding, deleting, replacing, or reordering any elements. 如果您在初始化 For Each ... Next 迴圈之後變更集合,則列舉值物件會變成無效,而下次嘗試存取專案會導致 @no__t 2 例外狀況。If you change the collection after you have initiated a For Each...Next loop, the enumerator object becomes invalid, and the next attempt to access an element causes an InvalidOperationException exception.

不過,這項修改封鎖不是由 Visual Basic 所決定,而是由 @no__t 0 介面的實作為。However, this blocking of modification isn't determined by Visual Basic, but rather by the implementation of the IEnumerable interface. 您可以使用允許在反復專案期間進行修改的方式來執行 IEnumerableIt is possible to implement IEnumerable in a way that allows for modification during iteration. 如果您考慮進行這類動態修改,請確定您瞭解所使用之集合上的 IEnumerable 實特性。If you are considering doing such dynamic modification, make sure that you understand the characteristics of the IEnumerable implementation on the collection you are using.

修改集合元素。Modifying Collection Elements. 列舉值物件的 Current 屬性是ReadOnly,它會傳回每個集合元素的本機複本。The Current property of the enumerator object is ReadOnly, and it returns a local copy of each collection element. 這表示您無法在 For Each ... Next 迴圈中修改元素本身。This means that you cannot modify the elements themselves in a For Each...Next loop. 您所做的任何修改只會影響 Current 的本機複本,而且不會反映回基礎集合中。Any modification you make affects only the local copy from Current and isn't reflected back into the underlying collection. 不過,如果專案是參考型別,您可以修改它所指向之實例的成員。However, if an element is a reference type, you can modify the members of the instance to which it points. 下列範例會修改每個 thisControl 元素的 @no__t 0 成員。The following example modifies the BackColor member of each thisControl element. 但是,您無法修改 thisControl 本身。You cannot, however, modify thisControl itself.

Sub LightBlueBackground(thisForm As System.Windows.Forms.Form)
    For Each thisControl In thisForm.Controls
        thisControl.BackColor = System.Drawing.Color.LightBlue
    Next thisControl
End Sub

上一個範例可以修改每個 thisControl 元素的 BackColor 成員,不過它無法修改 thisControl 本身。The previous example can modify the BackColor member of each thisControl element, although it cannot modify thisControl itself.

遍歷陣列。Traversing Arrays. 因為 @no__t 0 類別會執行 @no__t 1 介面,所以所有陣列都會公開 @no__t 2 方法。Because the Array class implements the IEnumerable interface, all arrays expose the GetEnumerator method. 這表示您可以使用 For Each ... Next 迴圈逐一查看陣列。This means that you can iterate through an array with a For Each...Next loop. 不過,您只能讀取陣列元素。However, you can only read the array elements. 您無法加以變更。You cannot change them.

範例Example

下列範例會列出 C:\ 中的所有資料夾目錄,方法是使用 DirectoryInfo 類別。The following example lists all the folders in the C:\ directory by using the DirectoryInfo class.

Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
    Debug.WriteLine(dir.Name)
Next

範例Example

下列範例說明排序集合的程序。The following example illustrates a procedure for sorting a collection. 此範例會排序儲存在 List<T> 中 @no__t 0 類別的實例。The example sorts instances of a Car class that are stored in a List<T>. Car 類別實作 IComparable<T> 介面,而這個介面要求實作 CompareTo 方法。The Car class implements the IComparable<T> interface, which requires that the CompareTo method be implemented.

@No__t-0 方法的每個呼叫都會進行用於排序的單一比較。Each call to the CompareTo method makes a single comparison that's used for sorting. 當目前物件和另一個物件比較時,在 CompareTo 方法中的使用者撰寫程式碼會傳回值。User-written code in the CompareTo method returns a value for each comparison of the current object with another object. 如果目前物件比另一個物件小則傳回的值小於零,如果目前物件比另一個物件大則傳回的值大於零,如果它們相等則傳回零。The value returned is less than zero if the current object is less than the other object, greater than zero if the current object is greater than the other object, and zero if they are equal. 這可讓您以程式碼定義大於、小於、等於的準則。This enables you to define in code the criteria for greater than, less than, and equal.

ListCars 方法中,cars.Sort() 陳述式會排序清單。In the ListCars method, the cars.Sort() statement sorts the list. List<T>Sort 方法的這個呼叫,會導致 CompareTo 方法對 ListCar 物件自動呼叫。This call to the Sort method of the List<T> causes the CompareTo method to be called automatically for the Car objects in the 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

另請參閱See also