Looping statements make the program execute a series of statements repeatedly. The loop can run for a fixed number of repetitions, run while some condition holds true, or run until some condition is true.
Broadly speaking, there are two types of looping statement.
For
A
While
loop executes while a condition is true or until a condition is met. Without a lot more information about the application, it is
The following sections describe the looping statements supported by Visual Basic .NET. The
The
For Next
loop is the most common type of looping statement in Visual Basic. The syntax is as
For
variable
[As
data_type
] =
start_value
To
stop_value
[Step
increment
]
statements
[Exit For]
statements
[Continue For]
statements
Next [
variable
]
The value
variable
is the looping variable that controls the loop. When the program
Normally, you would not intentionally write a loop that doesn’t execute, but this can occur when you use
For employee_num = 1 To num_employees ProcessEmployee(employee_num) Next employee_num
After it compares variable to stop_value , the program executes the statements inside the loop. It then adds increment to variable and starts the process over, again comparing variable to stop_value . If you omit increment , the program uses an increment of 1.
Note that
increment
can be negative or a
For i As Integer = 3 To 1 Step -0.5 Debug.WriteLine(i) Next i
If increment is positive, the program executes as long as variable <= stop_value . If increment is negative, the program executes as long as variable >= stop_value . This means that the loop would not execute infinitely if increment were to move variable away from stop_value . For example, in the following code start_value = 1 and increment = -1 . The variable i would take the values i=1 , i=0 , i=-1 , and so forth, so i will never reach the stop_value of 2. However, because increment is negative, the loop only executes while i>=2 . Because i starts with the value 1, the program immediately exits and the loop doesn’t execute at all.
For i As Integer = 1 To 2 Step -1 Debug.WriteLine(i) Next i
The program doesn’t need for you to include the variable’s
If you do not specify the looping variable’s data type in the For statement and you have Option Explicit turned on, you must declare the variable before the loop. For example, the following loop declares the variable i outside of the loop:
Dim i As Integer For i = 1 To 10 Debug.WriteLine(i) Next i
You cannot declare the same variable both inside and outside of a loop. If you declare a variable in the For statement, the variable’s scope is limited to the loop, and code outside of the loop cannot access the variable.
Declaring the variable in the For statement is a good practice. It limits the scope of the variable so you don’t need to remember what the variable is for in other pieces of code. It keeps the variable’s declaration close to the code where it is used, so it’s easier to remember the variable’s data type. It also lets you more easily reuse counter variables without fear of confusion. If you have several loops that need an arbitrarily named looping variable, they can all declare and use the variable i without interfering with each other.
The program calculates its start_value and stop_value before the loop begins and it never recalculates them, even if their values change. For example, the following code loops from 1 to this_ customer.Orders(1).NumItems . The program calculates this_customer.Orders(1).NumItems before executing the loop and doesn’t recalculate that value even if it later changes. This saves the program time, particularly for long expressions such as this one, which could take a noticeable amount of time to reevaluate each time through a long loop.
For item_num As Integer = 1 To this_customer.Orders(1).NumItems this_customer.ProcessItem(item_num) Next item_num
If you must reevaluate stop_value every time the loop executes, use a While loop.
The Exit For statement allows the program to leave a For loop before it would normally finish. For example, the following code loops through the employees array. When it finds an entry with the IsManager property set to True , it saves the employee’s index and uses Exit For to immediately stop looping.
Dim manager_index As Integer For i As Integer = employees.GetLowerBound(0) To _ employees.GetUpperBound(0) If employees(i).IsManager Then manager_index = i Exit For End If Next i
The
Exit For
statement exits only the
For
loop immediately
For i As Integer = 1 To 5 For j As Integer = 1 To 5 If i = j Then Exit For Debug.WriteLine("(" & i & ", " & j & ")") Next j Next i
The following shows this code’s result. You may want to walk through the code either mentally or in the debugger to convince yourself that this makes sense.
(2, 1)
(3, 1)
(3, 2)
(4, 1)
(4, 2)
(4, 3)
(5, 1)
(5, 2)
(5, 3)
(5, 4)
The Continue For statement makes the loop jump back to its For statement, increment its looping variable, and start the loop over again. This is particularly useful if the program doesn’t need to execute the rest of the steps within the loop and wants to quickly start the next iteration.
Your code can change the value of the control variable inside the loop, but that’s
Usually a For Next loop’s control variable is an integral data type such as an Integer or Long, but it can be any of the fundamental Visual Basic numeric data types. For example, the following code uses a variable declared as Single to display the values 1.0, 1.5, 2.0, 2.5, and 3.0:
For x As Single = 1 To 3 Step 0.5
Debug.WriteLine(x.ToString("0.0"))
Next x
Because floating-point
For x As Single = 1 To 2 Step 1 / 7
Debug.WriteLine(x)
Next x
One solution to this type of problem is to convert the code into a loop that uses an Integer control variable. Integer variables do not have the same problems with rounding errors that floating-point numbers do, so you have more precise control over the values used in the loop.
The following code does
Dim x As Single
x = 1
For i As Integer = 1 To 8
Debug.WriteLine(x)
x += CSng(1 / 7)
Next i
If you look at the value of variable x in the debugger, you will find that its real value during the last trip through the loop is roughly 2.0000001702989851. If this variable were controlling the For loop, the program would see that this value is greater than 2, so it would not display its final value.
A For Each loop iterates over the items in a collection, array, or other container class that supports For Each loops. The syntax is as follows:
For Each
variable
[As
object_type
] In
group
statements
[Exit For]
statements
[Continue For]
statements
Next [
variable
]
Here, group is a collection, array, or other object that supports For Each . As in For Next loops, the control variable must be declared either in or before the For statement.
To support For Each , the group object must implement the System.Collections.IEnumerable interface. This interface defines a GetEnumerator method that returns an enumerator. For more information, see the next section, “Enumerators.”
The control variable must be of a data type compatible with the objects contained in the group. If the group contains Employee objects, the variable could be an Employee object. It could also be a generic Object or any other class that readily converts into an Employee object. For example, if Employee inherits from the Person class, then the variable could be of type Person .
Visual Basic doesn’t automatically understand what kinds of objects are stored in a collection or array until it
For example, the following code creates a collection containing an Employee object and a Customer object. It then uses a For Each loop to display the name of each object. The control variable emp is of type Employee . The first time through the loop, the program sets emp equal to the collection’s Employee object and displays its name as expected. The second time through the loop, the program tries to set emp equal to the collection’s Customer object. That causes an “invalid cast exception.”
Dim people As New Collection
people.Add(New Employee("Alice Auxley"))
people.Add(New Customer("Bob Brentwood"))
For Each emp As Employee In people
Debug.WriteLine(emp.Name)
Next emp
When a collection or array contains more than one type of object (as in the previous example), the control variable must be of a type that can hold all of the objects. Assuming that the
Employee
and
Customer
classes in the previous example are not derived from a common
For Each person As Object In people
Debug.WriteLine(person.Name)
Next person
This code works as long as the Employee and Customer classes both have a Name property. However, if you have set Option Strict On , the compiler will complain because the generic Object class does not have a Name method. To avoid this error, you need to convert the generic Object variable into a specific type that does have the Name method.
The following code shows one way to use specific object types. The program uses the TypeOf statement to check the control variable’s class type. If the object has type Employee , then the code uses CType to convert the Object variable into an Employee object. It then uses that object’s Name method. Similarly, if the object is a Customer , the code uses CType to convert the generic Object into a Customer and uses its
Name
method.
Dim emp As Employee
For Each person As Object In people
If TypeOf person Is Employee Then
emp = CType(person, Employee)
Debug.WriteLine(emp.Name)
ElseIf TypeOf person Is Customer Then
Debug.WriteLine(CType(person, Customer).Name)
End If
Next person
You can use the Exit For statement to jump out of a For Each loop early. The following code loops through the employees collection using TypeOf to examine each object’s type. When it finds an object that has type Manager , the code saves a reference to the Manager object and uses Exit For to stop looping.
Dim a_manager As Manager
For Each emp As Employee in employees
If TypeOf emp Is Manager Then
a_manager = CType(emp, Manager)
Exit For
End If
Next emp
The Continue For statement makes the loop jump back to its For statement, fetch the next object from the collection, and start the loop over again. This is particularly useful if the program doesn’t need to execute the rest of the steps within the loop and wants to quickly start the next iteration.
You should not rely on the value of the looping variable outside of the loop, even if you declare the variable before the loop begins. After the loop ends in the current version of Visual Basic .NET, the variable contains a reference to the last object the code
This behavior is different from previous versions of Visual Basic, however. In Visual Basic 6, the looping variable is set to Nothing if the loop examines all the collection’s objects and finishes normally.
To avoid confusion and possibly subtle
You cannot declare the same variable both inside and outside of a For Each loop. If you declare a variable in the For Each statement, the variable’s scope is limited to the loop, and code outside of the loop cannot access the variable.
Declaring the variable in the For Each statement is a good practice. It limits the scope of the variable, so you don’t need to remember what the variable is for in other pieces of code. It keeps the variable’s declaration close to the code where it is used, so it’s easier to remember the variable’s data type. It also lets you more easily reuse counter variables without fear of confusion. If you have several loops that need an arbitrarily named looping variable, they can all declare and use the variable obj , person , or whatever else makes sense without interfering with each other.
Your code can change the value of the control variable inside the loop, but that has no effect on the loop’s progress through the collection or array. The loop resets the variable to the next object inside the group and continues as if you had never changed the variable’s value.
To avoid confusion, you should not change the control variable’s value, because that may lead other programmers to believe that you are trying to change the way the loop works through the group of objects. If you must do something more elaborate with an object, assign the control variable to a temporary variable and work with that instead. If you need to move arbitrarily through the group, consider using a While loop instead of a For Each loop.
Changes to a collection are immediately reflected in the loop. For example, if the statements inside the loop add a new object to the end of the collection, then the loop continues until it processes the new item. Similarly if the loop’s code
The exact effect on the loop depends on whether the item added or removed comes before or after the object the loop is currently processing. For example, if you remove an item before the current item, the loop has already examined that item, so there is no change to the loop. If you remove an item after the current one, the loop doesn’t examine it. If you remove the current item, the loop seems to get
Additions and deletions to an array are not reflected in the loop. If you use a ReDim statement to add items to the end of the array, the loop does not process them. If you try to access those objects, however, the program generates an “Index was outside the bounds of the array” error.
If you use ReDim to remove items from the end of the array, the loop processes those items anyway! If you modify the values in the array, for example, you change an object’s properties or set an array entry to an entirely new object, the loop sees the changes.
To avoid all these possible sources of confusion, don’t modify a collection or array while a For Each loop is examining its contents.
One common scenario when dealing with collections is examining every item in the collection and removing some of them. If you use a For Each loop, removing the loop’s current item makes the loop exit prematurely.
Another approach that seems like it might work (but doesn’t) is to use a For Next loop, as shown in the following code. If the code removes an object from the collection, the loop skips the next item because its index has been reduced by one and the loop has already passed that position in the collection. Worse still, the control variable i will increase until it reaches the original value of employees.Count . If the loop has removed any objects, the collection no longer holds that many items. The code tries to access an index beyond the end of the collection and throws an error.
Dim emp As Employee For i As Integer = 1 To employees.Count emp = CType(employees(i), Employee) If emp.IsManager Then employees.Remove(i) Next i
One solution to this problem is to use a
For Next
loop to examine the collection’s objects in reverse order, as shown in the following example. In this version, the code never needs to use an index after it has been deleted because it is counting
For i As Integer = employees.Count To 1 Step -1
emp = CType(employees(i), Employee)
If emp.IsManager Then employees.Remove(i)
Next i
An
enumerator
is an object that lets you move through the objects contained by some
You can use an enumerator to view the objects in a collection but not to modify the collection itself. You can use the enumerator to alter the objects in the collection, but you can generally not use it to add, remove, or rearrange the objects in the collection.
Initially, an enumerator is positioned before the first item in the collection. Your code can use the enumerator’s MoveNext method to step to the next object in the collection. MoveNext returns True if it successfully moves to a new object or False if there are no more objects in the collection.
The
Reset
method
The Current method returns the object that the enumerator is currently reading. Note that Current returns a generic Object, so you will probably need to use CType to convert the result into a more specific data type before you use it. Invoking Current throws an error if the enumerator is not currently reading any object. That happens when the enumerator is first created and it is before the first object, and after the enumerator has moved past the last object.
The following example uses an enumerator to loop through the items in a collection named m_Employees . It declares an Employee variable named emp and an IEnumerator object named employee_enumerator . It uses the collection’s GetEnumerator method to obtain an enumerator for the collection. The program then enters a While loop. If employee_enumerator.MoveNext returns True , the enumerator has successfully moved to the next object in the collection. As long as it has read an object, the program uses CType to convert the generic object returned by Current into an Employee object, and it displays the Employee object’s Title , FirstName , and LastName values. When it has finished processing all of the objects in the collection, employee_enumerator.MoveNext returns False and the While loop ends.
Dim emp As Employee Dim employee_enumerator As IEnumerator employee_enumerator = m_Employees.GetEnumerator() Do While (employee_enumerator.MoveNext) emp = CType(employee_enumerator.Current, Employee) Debug.WriteLine(emp.Title & " " & emp.FirstName & " " & emp.LastName) Loop
A For Each loop provides roughly the same access to the items in a container class as an enumerator. Under some circumstances, however, an enumerator may provide a more natural way to loop through a container class than a For Each loop. For example, an enumerator can skip several items without examining them closely. You can also use an enumerator’s Reset method to restart the enumeration. To restart a For Each loop, you would need to repeat the loop, possibly by placing it inside yet another loop that determined when to stop looping.
The Visual Basic documentation states that an enumerator is valid only as long as you do not modify the collection. If you add or remove an object to or from the collection, the enumerator throws an “invalid operation” exception the next time you use it. In at least some cases, however, this doesn’t seem to be true, and an enumerator can still work even if you modify its collection. This could lead to extremely confusing situations, however. To avoid unnecessary confusion, do not modify a collection while you are accessing it with an enumerator.
The IEnumerable interface defines the features needed for enumerators so any class that implements the IEnumerable interface provides enumerators. Any class that supports For Each must also implement the IEnumerable interface, so any class that supports For Each also supports enumerators. A few of the classes that implement IEnumerable include the following:
Array
HybridDictionary
SqlDataReader
ArrayList
ListDictionary
Stack
Collection
MessageQueue
String
CollectionBase
OdbcDataReader
StringCollection
ControlCollection
OleDbDataReader
StringDictionary
DataView
OracleDataReader
TableCellCollection
DictionaryBase
Queue
TableRowCollection
DictionaryEntries
ReadOnlyCollectionBase
XmlNode
Hashtable
SortedList
XmlNodeList
An
iterator
is similar in concept to an enumerator. It also provides
For example, a GraphicsPath object represents a series of connected lines and curves. A GraphicsPathIterator object can step through the line and curve data contained in a GraphicsPath object.
Iterators are much more specialized than enumerators. How you use them depends on what you need to do and on the kind of iterator, so they are not described in detail here.
Visual Basic .NET supports three basic forms of Do Loop statements. The first form is a loop that repeats forever. The syntax is as follows:
Do
statements
[Exit Do]
statements
[Continue Do]
statements
Loop
This kind of Do Loop executes the code it contains until the program somehow ends the loop. The following loop processes work orders. It calls the WorkOrderAvailable function to see if a work order is available. If an order is available, the code calls ProcessWorkOrder to process it. The code then repeats the loop to look for another work order.
Do
' See if a work order is available.
If WorkOrderAvailable() Then
' Process the next work order.
ProcessWorkOrder()
End If
Loop
This example keeps checking for work orders forever. Most programs include some method for the loop to end so that the program can eventually stop. For example, the loop might use the
Exit Do
statement described shortly to end the loop if the
The second and third forms of Do Loop statements both include a test to determine whether they should continue looping. The difference between the two versions is where they place the test.
The second version of Do Loop places its test at the beginning, so the test is evaluated before the code is executed even once. If the test initially indicates that the loop should not continue, the statements inside the loop are never executed. The syntax is as follows:
Do {While Until}
condition
statements
[Exit Do]
statements
[Continue Do]
statements
Loop
The final version of
Do Loop
places its test at the end. In this version, the statements inside the loop are executed before the loop
Do
statements
[Exit Do]
statements
[Continue Do]
statements
Loop {While Until}
condition
If the code uses the While keyword, the loop executes as long as the condition is true. If the code uses the Until keyword, the loop executes as long as the condition is false. Note that the statement Until condition is equivalent to While Not condition . Visual Basic provides these two variations so that you can pick the one that makes your code more readable. Use the one that makes the most sense to you.
The Exit Do statement allows the program to leave a loop before it would normally finish. For example, the following code uses an enumerator to look through the m_Employees collection. If it finds an Employee object that has title Manager , it exits the Do While Loop . Note that the loop eventually exits whether it finds a manager or not, so the code must later check to see if it found a manager.
Dim emp As Employee
Dim employee_enumerator As IEnumerator
employee_enumerator = m_Employees.GetEnumerator()
Do While (employee_enumerator.MoveNext)
emp = CType(employee_enumerator.Current, Employee)
If emp.Title = "Manager" Then Exit Do
Loop
' Process the Manager.
If emp.Title = "Manager" Then ...
The Exit Do statement exits only the Do Loop immediately surrounding the statement. For example, the following code makes the variable R run from 1 to 10. For each value of R , the program makes variable C run from 1 to 100. Within the inner loop, the program checks cost(R, C) . If that value is greater than 100, the program displays R , C , and cost(R, C) and then uses Exit Do to stop the inner loop. The loop over C ends and the code continues with the next value of R .
R = 1 Do While R < 10 C = 1 Do While C < 100 If cost(R, C) > 100 Then Debug.WriteLine("(" & R & ", " & C & ") = " & cost(R, C)) End If Loop Loop
The Continue Do statement makes the loop jump back to its Do statement and start the loop over again. This is particularly useful if the program doesn’t need to execute the rest of the steps within the loop and wants to quickly start the next iteration. Unlike a For loop, the Do loop does not automatically increment a looping variable or move to the next object in a collection. The code must explicitly change the loop’s condition before calling Continue Do or else the loop will continue forever.
A While End loop is equivalent to a Do While Loop . The syntax is as follows:
While
condition
statements
[Exit While]
statements
[Continue While]
statements
End While
This is equivalent to the following:
Do While
condition
statements
[Exit Do]
statements
Loop
The End While statement exits a While End loop just as an Exit Do statement exits a Do While Loop .
The difference between While End and Do While Loop is stylistic, and you can use whichever seems clearer to you. Because Do Loop provides more flexibility, having four different versions using While or Until at the start or finish of the loop, you might want to stick to them for consistency’s sake.
Previous versions of Visual Basic ended While loops with the Wend keyword, as in the following Visual Basic 6 code:
i = 1
While i < 5
Debug.Print i
i = i + 1
Wend
The Wend keyword is no longer supported, so you should use End While instead.
The Exit statement lets you end a loop early. The Continue statement lets you jump to the start of a loop before reaching its end.
Both of these statements work on the innermost loop of the appropriate type. For example, the following code contains a For loop, that contains Do loop, that contains a second For loop. Within the innermost loop, an Exit For statement exits the inner For loop. An Exit Do statement exits the Do loop. There is no simple Exit statement that can exit the outer For loop from this position.
For i As Integer = 1 To 3 Dim j As Integer = 1 Do While j < 3 For k As Integer = 1 To 3 '... If test1 Then Exit For ' Exits the For K loop. '... If test2 Then Exit Do ' Exits the Do. '... Next k Loop Next i
Similarly, a Continue statement continues the innermost loop of the appropriate type: For , Do , or While .
A
GoTo
statement unconditionally tells the program to jump to a specific location in the code. Because it
GoTo
line_label
...
line_label
: ...
While
GoTo
by itself isn’t a decision statement, it is often used to
If purchase_total < 1000 Then GoTo SmallOrder
' Process a large order.
...
Exit Sub
SmallOrder:
' Process a small order.
...
The following code does roughly the same thing as the previous version but without the GoTo statement:
If purchase_total < 1000 Then ' Process a large order. ... Else ' Process a small order. ... End If
Similarly, GoTo is sometimes used to build a loop. The following code uses GoTo to jump backward in the code to call subroutine DoSomething 10 times:
Dim i As Integer = 1
StartLoop:
DoSomething()
i += 1
If i <= 10 Then GoTo StartLoop
The following code does the same thing without the GoTo statement:
For i As Integer = 1 To 10
DoSomething()
Next i
The problem with the
GoTo
statement is its flexibility. By using
GoTo
in a haphazard way, an undisciplined programmer can make the program jump all over the place with little
Many programming groups prohibit any use of
GoTo
because it can lead to this kind of code. Some even believe
GoTo
should be removed from the Visual Basic language. You can always use
If Then
Else
statements,
For Next
loops,
While
loops, and other control statements in place of
GoTo
statements, so
GoTo
is not
However, some programmers feel that
GoTo
' Get started, open database, open files, etc.
Initialize()
' Perform a long series of tasks.
DoStuff1()
If should_stop Then GoTo CleanUp
DoStuff2()
If should_stop Then GoTo CleanUp
DoStuff3()
If should_stop Then GoTo CleanUp
...
CleanUp: ' Close database, delete tempporary files, etc. PerformCleanUp()
The
GoTo
statement in this code lets the program jump to the clean-up code any time it needs to stop performing its tasks. That may be because a task failed, the user
Note that this is a very specific use of GoTo . The code only jumps forward, never backward. It also only jumps to clean-up code, not to some arbitrary point in the code. These facts help make the GoTo statement easier to understand and prevent spaghetti code.
The following code does the same thing as the previous version without using GoTo . At each step, the program checks the value of should_stop to see if it should continue working through its tasks.
' Get started, open database, open files, etc.
Initialize()
' Perform a long series of tasks.
DoStuff1()
If Not should_stop Then DoStuff2()
If Not should_stop Then DoStuff3()
' Close database, delete tempporary files, etc.
PerformCleanUp()
The following code shows another version that doesn’t use GoTo . This version places the code that formerly contained the GoTo statement in a new subroutine. Instead of using GoTo , this routine uses Exit
Sub
to stop performing tasks early if necessary.
Sub DoWork()
' Get started, open database, open files, etc.
Initialize()
' Perform all of the tasks.
PerformTasks()
' Close database, delete tempporary files, etc.
PerformCleanUp()
End Sub
' Perform a long series of tasks.
Sub PerformTasks()
DoStuff1()
If should_stop Then Exit Sub
DoStuff2()
If should_stop Then Exit Sub
DoStuff3()
If should_stop Then Exit Sub
End Sub
Conceptually, an Exit Sub statement is little different from a GoTo statement. After all, it, too, is an unconditional jump command. However, Exit Sub has a very specific, well-known effect: It makes the program stop executing the current subroutine. It cannot make the program jump around arbitrarily, possibly leading to spaghetti code.
If you ever feel tempted to use
GoTo
, take a few moments to think about ways you might rewrite the code. If the only ways you can think of to rewrite the code are more confusing than the original version, go ahead and use
GoTo
. You should probably add some