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 |
Required in the For Each statement. Optional in the Next statement. Variable. Used to iterate through the elements of the collection. |
datatype |
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. The data type of element . |
group |
Required. A variable with a type that's a collection type or Object. Refers to the collection over which the statements are to be repeated. |
statements |
Optional. One or more statements between For Each and Next that run on each item in group . |
Continue For |
Optional. Transfers control to the start of the For Each loop. |
Exit For |
Optional. Transfers control out of the For Each loop. |
Next |
Required. Terminates the definition of the For Each loop. |
Simple Example
Use a For Each
...Next
loop when you want to repeat a set of statements for each element of a collection or array.
Tip
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. In this kind of case, a For Each
...Next
loop is often a better choice.
In the following example, the For Each
…Next
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
You can nest For Each
loops by putting one loop within another.
The following example demonstrates nested For Each
…Next
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
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
The Exit For statement causes execution to exit the For
…Next
loop and transfers control to the statement that follows the Next
statement.
The Continue For
statement transfers control immediately to the next iteration of the loop. For more information, see Continue Statement.
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 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
You can put any number of Exit For
statements in a For Each
loop. 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
is often used after an evaluation of some condition, for example, in an If
...Then
...Else
structure. You 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.
An exception is caught in a
Try
...Catch
...Finally
. You might useExit For
at the end of theFinally
block.There an endless loop, which is a loop that could run a large or even infinite number of times. If you detect such a condition, you can use
Exit For
to escape the loop. For more information, see Do...Loop Statement.
Iterators
You use an iterator to perform a custom iteration over a collection. An iterator can be a function or a Get
accessor. It uses a Yield
statement to return each element of the collection one at a time.
You call an iterator by using a For Each...Next
statement. Each iteration of the For Each
loop calls the iterator. 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.
The following example uses an iterator function. The iterator function has a Yield
statement that's inside a For…Next loop. 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
For more information, see Iterators, Yield Statement, and Iterator.
Technical Implementation
When a For Each
…Next
statement runs, Visual Basic evaluates the collection only one time, before the loop starts. If your statement block changes element
or group
, these changes don't affect the iteration of the loop.
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.
If Option Infer is on (its default setting), the Visual Basic compiler can infer the data type of element
. If it is off and element
hasn't been declared outside the loop, you must declare it in the For Each
statement. To declare the data type of element
explicitly, use an As
clause. Unless the data type of element is defined outside the For Each
...Next
construct, its scope is the body of the loop. Note that you cannot declare element
both outside and inside the loop.
You can optionally specify element
in the Next
statement. This improves the readability of your program, especially if you have nested For Each
loops. You must specify the same variable as the one that appears in the corresponding For Each
statement.
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. Changing the value of group
doesn't affect the collection or its elements, which were determined when the loop was first entered.
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. However, the compiler can detect this overlapping error only if you specify element
in every Next
statement.
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. The order of traversal isn't determined by Visual Basic, but by the MoveNext method of the enumerator object. 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. You might achieve more reliable results using a different loop structure, such as For
...Next
or Do
...Loop
.
The runtime must be able to convert the elements in group
to element
. 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.
The data type of group
must be a reference type that refers to a collection or an array that's enumerable. 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
defines the GetEnumerator method, which returns an enumerator object for the collection. 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 uses these to traverse the collection.
Narrowing Conversions
When Option Strict
is set to On
, narrowing conversions ordinarily cause compiler errors. 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.
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. 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
. 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
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 Calls
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. Otherwise, it calls the MoveNext method and the Current property of the enumerator object to return the first element. 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. Otherwise, Visual Basic sets element
to the first element and runs the statement block.
Each time Visual Basic encounters the Next
statement, it returns to the For Each
statement. 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. This process continues until MoveNext
indicates that there is no next element or an Exit For
statement is encountered.
Modifying the Collection. The enumerator object returned by GetEnumerator normally doesn't let you change the collection by adding, deleting, replacing, or reordering any elements. 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.
However, this blocking of modification isn't determined by Visual Basic, but rather by the implementation of the IEnumerable interface. It is possible to implement IEnumerable
in a way that allows for modification during iteration. 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. The Current property of the enumerator object is ReadOnly, and it returns a local copy of each collection element. This means that you cannot modify the elements themselves in a For Each
...Next
loop. 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. The following example modifies the BackColor
member of each thisControl
element. 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
The previous example can modify the BackColor
member of each thisControl
element, although it cannot modify thisControl
itself.
Traversing Arrays. Because the Array class implements the IEnumerable interface, all arrays expose the GetEnumerator method. 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 1
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 2
The following example illustrates a procedure for sorting a collection. The example sorts instances of a Car
class that are stored in a List<T>. The Car
class implements the IComparable<T> interface, which requires that the CompareTo method be implemented.
Each call to the CompareTo method makes a single comparison that's used for sorting. 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.
In the ListCars
method, the cars.Sort()
statement sorts the list. 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