共用方式為


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

針對集合中的每個元素,重複一組陳述式。

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

組件

詞彙

定義

element

在 For Each 陳述式中為必要項。 在 Next 陳述式中是選擇項。 變數。 用來逐一查看集合的項目。

datatype

如果尚未宣告 element,則為必要項。 element 的資料型別。

group

必要項。 物件變數。 請參考要重複 statements 的集合。

statements

選擇項。 在 For Each 和 Next 中,有一個或多個陳述式在 group 的每個項目上執行。

Continue For

選擇項。 將控制轉移至 For Each 迴圈的開頭。

Exit For

選擇項。 從 For Each 迴圈當中傳出控制權。

Next

必要項。 結束 For Each 迴圈的定義。

備註

當您要重複執行集合或陣列之每個項目的一組陳述式時,請使用 For Each...Next 迴圈 (Loop)。

在迴圈開始之前,Visual Basic 只會評估集合一次。 如果陳述式區塊變更 element 或 group,這些變更不會影響迴圈的反覆運算。

當集合中所有的項目都已連續指派給 element 時,For Each 迴圈會停用,並且控制權會傳遞至 Next 陳述式隨後的陳述式。

如果尚未在這個迴圈外宣告 element,就必須在 For Each 陳述式中宣告它。 您可以使用 As 陳述式明確宣告 element 的型別,或者依據型別推斷指派型別。 不論哪個情況,element 的範圍即是迴圈的主體。 但不能在迴圈內外宣告 element。

您可以在 Next 陳述式中選擇性地指定 element。 這能提高程式的可讀性,尤其是在您具有巢狀 For Each 迴圈時。 所指定的變數必須和相對應之 For Each 陳述式中出現的變數相同。

您可能想要避免在迴圈內變更 element 的值。 這樣做可能會讓程式碼更難以閱讀和偵錯。 變更 group 的值不會影響集合或它的項目,這是初次進入迴圈時要判斷的項目。

秘訣秘訣

當您可以使迴圈的每個反覆運算與控制項變數產生關聯,並判斷變數的初始值和最終值時,For...Next 陳述式 (Visual Basic) 就能順利工作。 不過,若您正在處理集合,則初始值和最終值的概念就沒有意義,而且不需要知道集合會具有多少個項目。 在上述情形中,For Each...Next 迴圈是較好的選擇。

如果程式碼需要以特定順序周遊集合,則 For Each...Next 迴圈不是最佳選擇 (除非您了解集合公開之列舉程式物件的特性)。 周遊順序不是由 Visual Basic 判斷,而是由列舉程式物件的 MoveNext 方法判斷。 因此您可能無法預測哪一個集合項目會在 element 中第一個傳回,或者哪一個項目會接在指定之項目後傳回。 使用不同的迴圈結構 (例如,For...Next 或 Do...Loop),可以獲得更可靠的結果.

巢狀迴圈

您可以將一個迴圈置於另一個迴圈內,使 For Each 迴圈套疊成巢狀。 不過,每個迴圈必須具備唯一的 element 變數。

您可以將不同類型的控制結構相互套疊成巢狀。 如需詳細資訊,請參閱巢狀控制結構 (Visual Basic)

如果先發現外部巢狀層次的 Next 陳述式才發現內部層次的 Next,編譯器會發出錯誤的信號。 但是,只有當您在每個 Next 陳述式中指定 element 時,編譯器才會偵測到這個重疊錯誤。

Exit For

Exit For 陳述式會使執行離開 For…Next 迴圈,並將控制權轉移給 Next 陳述式隨後的陳述式。

您可以將任意數目的 Exit For 陳述式放在 For Each 迴圈中。 用於巢狀的 For Each 迴圈內時,Exit For 會使程式執行退出最內層的迴圈,並將控制權轉移到下一個較高的巢狀層次。

Exit For 通常會在評估一些條件之後使用,例如 If...Then...Else 結構。 在下列情況中,您可能會想要使用 Exit For:

  • 繼續逐一查看則沒有必要或是不可行。 這可能是因為錯誤值或終止要求所造成。

  • 在 Try...Catch...Finally 中攔截到例外狀況。 您可能在 Finally 區塊的結尾處使用 Exit For。

  • 發生無止盡迴圈,這是可以執行龐大甚或無限次數的迴圈。 如果您偵測到這類狀況,可以使用 Exit For 逸出此迴圈。 如需詳細資訊,請參閱Do...Loop 陳述式 (Visual Basic)

Continue For 陳述式會立即將控制權轉移至迴圈的下一個反覆運算。 如需詳細資訊,請參閱Continue 陳述式 (Visual Basic)

資料型別

element 的資料型別必須是可將 group 的項目轉換成它的資料型別。

group 的資料型別必須是有參考集合或可列舉之陣列的參考型別。 這通常表示該 group 參考至實作 System.Collections 命名空間之 IEnumerable 介面或 System.Collections.Generic 命名空間之 IEnumerable<T> 介面的物件。 System.Collections.IEnumerable 定義 GetEnumerator 方法,該方法會傳回集合的列舉值物件。 列舉值物件會實作 System.Collections 命名空間的 System.Collections.IEnumerator 介面,並公開 (Expose) Current 屬性和 ResetMoveNext 方法。 Visual Basic 使用這些屬性和方法來周遊集合。

group 的項目通常是 Object 型別,不過可以具有任何執行階段資料型別。

縮小轉換

當 Option Strict 設定為 On,縮小轉換通常會造成編譯器錯誤。 不過,在 For Each 陳述式中,由 group 中項目變成 element 的轉換作業會在執行階段評估與執行,並隱藏縮小轉換造成的編譯器錯誤。

在下列範例中,由於將 Long 轉換為 Integer 是縮小轉換,因此當 Option Strict 是 On 時,將 m 指派為 n 初始值的作業不會編譯。 但是在 For Each 陳述式中,即使需要進行從 Long 到 Integer 的相同轉換才能指派 number,也不會報告任何編譯器錯誤。 在數字很大的 For Each 陳述式中,將 ToInteger 套用至該數字時會發生執行階段錯誤。

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 呼叫

開始執行 For Each...Next 迴圈時,Visual Basic 會驗證 group 是否參考有效的集合物件。 如果沒有,會擲回例外狀況。 否則,會呼叫 MoveNext 方法和列舉值物件的 Current 屬性,傳回第一個項目。 如果 MoveNext 指出沒有下一個項目,也就是說,集合是空的,則 For Each 迴圈會停止,且控制權會傳遞至 Next 陳述式隨後的陳述式。 否則,Visual Basic 會將 element 設為第一個項目,並執行陳述式區塊。

Visual Basic 每次遇到 Next 陳述式時,就會回到 For Each 陳述式。 接著再次呼叫 MoveNextCurrent 傳回下一個項目,並根據結果重新執行區塊或停止迴圈。 此處理序會繼續執行,直到 MoveNext 指出沒有下一個項目,或是遇到 Exit For 陳述式為止。

修改

修改集合GetEnumerator 傳回的列舉程式物件通常不允許您經由新增、刪除、取代或重新排列任何項目的方式變更集合。 如果您在初始 For Each...Next 迴圈後變更集合,列舉程式物件會變成無效,而且在下次嘗試存取項目時會引發 InvalidOperationException 例外狀況。

但是,不允許修改並不是由 Visual Basic 決定,而是由 IEnumerable 介面的實作 (Implementation) 方式決定。 您也可以實作 IEnumerable,允許在反覆運算時進行修改。 如果您考慮要進行這類動態修改,對於您所使用的集合,請務必了解 IEnumerable 實作的特性。

修改集合項目列舉程式物件的 Current 屬性是 ReadOnly (Visual Basic),而且它會傳回每一個集合項目的本機複本。 這表示您無法在 For Each...Next 迴圈中修改項目本身。 您所做的任何修改只會影響 Current 的本機複本,而不會反映回基礎集合中。 然而,如果項目是參考型別,您可以修改它所指向的執行個體成員。 下列範例將說明這點。

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

上述範例可以修改每個 thisControl 項目的 BackColor 成員,不過它無法修改 thisControl 本身。

走訪陣列因為 Array 類別會實作 IEnumerable 介面,因此全部的陣列都會公開 GetEnumerator 方法。 這表示您可以使用 For Each...Next 逐一查看陣列。 不過,您只能讀取陣列元素。 您無法加以變更。 如需說明,請參閱 HOW TO:在集合或陣列中執行各元素的多個陳述式 (Visual Basic)

範例

下列範例顯示如何使用 For Each…Next 陳述式。

' 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…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 

下列範例示範如何使用 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 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

下列範例會使用 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

下列範例示範如何使用 IComparable 介面排序集合。

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
        ' Determine the relative order of the objects being compared.
        ' This is used to 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

下列範例包含具有自訂列舉程式的自訂集合類別。

Public Sub ListColors()
    Dim colors As New AllColors()

    For Each theColor As Color In colors
        Debug.Write(theColor.Name & " ")
    Next
    Debug.WriteLine("")
    ' Output: red blue green
End Sub

' Collection class.
Public Class AllColors
    Implements System.Collections.IEnumerable

    Private _colors() As Color =
    {
        New Color With {.Name = "red"},
        New Color With {.Name = "blue"},
        New Color With {.Name = "green"}
    }

    Public Function GetEnumerator() As System.Collections.IEnumerator _
        Implements System.Collections.IEnumerable.GetEnumerator

        Return New ColorEnumerator(_colors)

        ' Instead of creating a using a custom enumerator, you could
        ' use the GetEnumerator of the array.
        'Return _colors.GetEnumerator
    End Function

    ' Custom enumerator.
    Private Class ColorEnumerator
        Implements System.Collections.IEnumerator

        Private _colors() As Color
        Private _position As Integer = -1

        Public Sub New(ByVal colors() As Color)
            _colors = colors
        End Sub

        Public ReadOnly Property Current() As Object Implements System.Collections.IEnumerator.Current
            Get
                Return _colors(_position)
            End Get
        End Property

        Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
            _position += 1
            Return (_position < _colors.Length)
        End Function

        Public Sub Reset() Implements System.Collections.IEnumerator.Reset
            _position = -1
        End Sub
    End Class
End Class

' Element class.
Public Class Color
    Public Property Name As String
End Class

請參閱

工作

HOW TO:在集合或陣列中執行各元素的多個陳述式 (Visual Basic)

參考

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

While...End While 陳述式 (Visual Basic)

Do...Loop 陳述式 (Visual Basic)

概念

迴圈結構 (Visual Basic)

Visual Basic 中的集合

擴展和縮小轉換 (Visual Basic)

物件初始設定式:具名和匿名型別 (Visual Basic)

集合初始設定式概觀 (Visual Basic)

Visual Basic 中的陣列

變更記錄

日期

記錄

原因

2010 年 12 月

已重新組織<備註>一節並加入範例。

資訊加強。