Instrucción For Each...Next (Visual Basic)
Repite un grupo de instrucciones para cada elemento de una colección.
Sintaxis
For Each element [ As datatype ] In group
[ statements ]
[ Continue For ]
[ statements ]
[ Exit For ]
[ statements ]
Next [ element ]
Partes
| Término | Definición |
|---|---|
element |
Requerido en la For Each instrucción . Opcional en la Next instrucción . Variable. Se usa para recorrer en iteración los elementos de la colección. |
datatype |
Opcional si está en (valor predeterminado) o ya está declarado; obligatorio si está desactivado y Option Infer element aún no está Option Infer element declarado. El tipo de datos de element. |
group |
Necesario. Variable con un tipo que es un tipo de colección o object. Hace referencia a la colección en la que statements se va a repetir . |
statements |
Opcional. Una o varias instrucciones entre For Each y que se ejecutan en cada elemento de Next group . |
Continue For |
Opcional. Transfiere el control al inicio del For Each bucle. |
Exit For |
Opcional. Transfiere el control fuera del For Each bucle. |
Next |
Necesario. Finaliza la definición del For Each bucle. |
Ejemplo sencillo
Use un bucle ... cuando desee repetir un conjunto de instrucciones For Each para cada elemento de una colección o Next matriz.
Sugerencia
Un para... Next Statement funciona bien cuando puede asociar cada iteración de un bucle a una variable de control y determinar los valores iniciales y finales de esa variable. Sin embargo, cuando se trabaja con una colección, el concepto de valores iniciales y finales no es significativo y no se sabe necesariamente cuántos elementos tiene la colección. En este tipo de caso, un For Each bucle ... suele ser una mejor Next opción.
En el ejemplo siguiente, For Each el ...Next La instrucción recorre en iteración todos los elementos de una colección 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
Para obtener más ejemplos, vea Colecciones y matrices.
Nested Loops
Puede For Each anidar bucles colocando un bucle dentro de otro.
En el ejemplo siguiente se muestra For Each ...Next Estructuras.
' 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
Al anidar bucles, cada bucle debe tener una element variable única.
También puede anidar diferentes tipos de estructuras de control entre sí. Para obtener más información, vea Estructuras de control anidadas.
Salir de y continuar para
La instrucción Exit For hace que la ejecución salga de For ...Next loop y transfiere el control a la instrucción que sigue a la Next instrucción .
La Continue For instrucción transfiere el control inmediatamente a la siguiente iteración del bucle. Para obtener más información, vea Continue (Instrucción).
En el ejemplo siguiente se muestra cómo usar las Continue For Exit For instrucciones y .
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
Puede colocar cualquier número de Exit For instrucciones en un For Each bucle. Cuando se usa en bucles anidados, hace que la ejecución salga del bucle más interno y transfiere For Each el control al siguiente nivel superior de Exit For anidamiento.
Exit For a menudo se usa después de una evaluación de alguna condición, por ejemplo, en un If ... Then ...Else Estructura. Es posible que quiera usar Exit For para las condiciones siguientes:
Seguir iterar es innecesario o imposible. Esto puede deberse a un valor erróneo o a una solicitud de finalización.
Se detecta una excepción en
Tryun elemento ...Catch...Finally. Puede usarExit Foral final delFinallybloque.Hay un bucle sin fin, que es un bucle que podría ejecutar un número grande o incluso infinito de veces. Si detecta esta condición, puede usar para escapar
Exit Forel bucle. Para obtener más información, vea Do... Instrucción de bucle.
Iterators
Se usa un iterador para realizar una iteración personalizada en una colección. Un iterador puede ser una función o un Get accessor. Usa una instrucción Yield para devolver cada elemento de la colección de uno en uno.
Se llama a un iterador mediante una For Each...Next instrucción . Cada iteración del bucle For Each llama al iterador. Cuando se Yield alcanza una instrucción en el iterador, se devuelve la expresión de la instrucción y se conserva la ubicación actual en el Yield código. La ejecución se reinicia desde esa ubicación la próxima vez que se llama al iterador.
En el ejemplo siguiente se usa una función de iterador. La función de iterador tiene Yield una instrucción que está dentro de for... Bucle siguiente. En el método , cada iteración del cuerpo de la instrucción crea una llamada a la función ListEvenNumbers For Each iterador, que continúa con la instrucción Yield siguiente.
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
Para obtener más información, vea Iterators, Yield Statemente Iterator.
Implementación técnica
Cuando un For Each ...Next la instrucción se ejecuta Visual Basic evalúa la colección solo una vez, antes de que se inicie el bucle. Si la instrucción bloquea los cambios o , estos cambios element no afectan a la group iteración del bucle.
Cuando todos los elementos de la colección se han asignado sucesivamente a , el bucle se detiene y el control pasa a element la instrucción que sigue a la instrucción For Each Next .
Si Option Infer está en (su configuración predeterminada), el Visual Basic puede deducir el tipo de datos de element . Si está desactivado y no se ha declarado fuera del element bucle, debe declararlo en la For Each instrucción . Para declarar el tipo de datos element de explícitamente, use una As cláusula . A menos que el tipo de datos del elemento se defina fuera de For Each la construcción ... , su ámbito es el cuerpo del Next bucle. Tenga en cuenta que no puede element declarar tanto fuera como dentro del bucle.
Opcionalmente, puede especificar element en la Next instrucción . Esto mejora la legibilidad del programa, especialmente si tiene For Each bucles anidados. Debe especificar la misma variable que la que aparece en la instrucción For Each correspondiente.
Es posible que quiera evitar cambiar el valor de element dentro de un bucle. Esto puede dificultar la lectura y depuración del código. Cambiar el valor de no afecta a la colección ni a sus elementos, que se determinaron cuando se escribió group por primera vez el bucle.
Cuando se anidan bucles, si se encuentra una instrucción de un nivel de anidamiento externo antes del de un nivel interno, el compilador señala Next Next un error. Sin embargo, el compilador puede detectar este error superpuesto solo si se especifica element en cada Next instrucción .
Si el código depende de recorrer una colección en un orden determinado, un bucle ... no es la mejor opción, a menos que conozca las características del objeto enumerador que expone la For Each Next colección. El orden del recorrido no viene determinado por Visual Basic, sino por el MoveNext método del objeto enumerador. Por lo tanto, es posible que no pueda predecir qué elemento de la colección es el primero que se devuelve en , o que es el siguiente que se va a devolver después de element un elemento determinado. Puede lograr resultados más confiables mediante una estructura de bucles diferente, como For ... Next o ... Do Loop .
El tiempo de ejecución debe poder convertir los elementos de group en element . La instrucción [ ] controla si se permiten las conversiones de ampliación y de reducción ( está desactivada, su valor predeterminado) o si solo se permiten conversiones de ampliación Option Strict Option Strict ( está Option Strict en). Para obtener más información, vea Conversiones de reducción.
El tipo de datos de debe ser un tipo de referencia que haga referencia group a una colección o una matriz enumerable. Normalmente esto significa que hace referencia a un objeto que implementa la interfaz del espacio de nombres group o la interfaz del espacio de IEnumerable System.Collections IEnumerable<T> System.Collections.Generic nombres. System.Collections.IEnumerable define el GetEnumerator método , que devuelve un objeto enumerador para la colección. El objeto enumerador implementa la interfaz del espacio de System.Collections.IEnumerator nombres y expone la propiedad y los System.Collections Current Reset MoveNext métodos y . Visual Basic los usa para recorrer la colección.
conversiones de restricción
Cuando Option Strict se establece en , las conversiones de On limitación normalmente provocan errores del compilador. Sin embargo, en una instrucción , las conversiones de los elementos de a se evalúan y realizan en tiempo de ejecución, y se suprimen los errores del compilador causados por conversiones For Each group de element limitación.
En el ejemplo siguiente, la asignación de como el valor inicial de no se compila cuando está en porque la conversión de m a es una conversión de n Option Strict Long Integer limitación. Sin embargo, en la instrucción no se notifica ningún error del compilador, aunque la asignación a For Each requiere la misma conversión de a number Long Integer . En la instrucción que contiene un número grande, se produce un error en tiempo de ejecución For Each cuando se aplica al número ToInteger grande.
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
Llamadas de IEnumerator
Cuando se inicia la For Each ejecución de un bucle ... , Visual Basic comprueba que hace referencia a un objeto de colección Next group válido. Si no es así, produce una excepción. De lo contrario, llama MoveNext al método y a la propiedad del objeto Current enumerador para devolver el primer elemento. Si indica que no hay ningún elemento siguiente, es decir, si la colección está vacía, el bucle se detiene y el control pasa a la instrucción que sigue MoveNext For Each a la instrucción Next . De lo contrario, Visual Basic element establece en el primer elemento y ejecuta el bloque de instrucciones.
Cada vez Visual Basic encuentra la Next instrucción , vuelve a la instrucción For Each . De nuevo llama a y para devolver el siguiente elemento y, de nuevo, ejecuta el bloque o detiene MoveNext el bucle en función del Current resultado. Este proceso continúa MoveNext hasta que indica que no hay ningún elemento siguiente o se encuentra una instrucción Exit For .
Modificar la colección. Normalmente, el objeto enumerador devuelto por no permite cambiar la colección agregando, eliminando, reemplazando ni GetEnumerator reordenando ningún elemento. Si cambia la colección después de haber iniciado un bucle ... , el objeto enumerador deja de ser válido y el siguiente intento de obtener acceso a un elemento For Each Next produce una InvalidOperationException excepción.
Sin embargo, este bloqueo de la modificación no viene determinado por Visual Basic, sino por la implementación de la IEnumerable interfaz . Es posible implementar de una IEnumerable manera que permita la modificación durante la iteración. Si está pensando en realizar esta modificación dinámica, asegúrese de que comprende las características de la implementación IEnumerable en la colección que está usando.
Modificar elementos de colección. La Current propiedad del objeto enumerador es ReadOnlyy devuelve una copia local de cada elemento de colección. Esto significa que no se pueden modificar los elementos en un For Each bucle Next ... . Cualquier modificación que realice afecta solo a la copia local de y no se refleja Current de nuevo en la colección subyacente. Sin embargo, si un elemento es un tipo de referencia, puede modificar los miembros de la instancia a la que apunta. En el ejemplo siguiente se modifica el BackColor miembro de cada thisControl elemento. Sin embargo, no se puede thisControl modificar a sí mismo.
Sub LightBlueBackground(thisForm As System.Windows.Forms.Form)
For Each thisControl In thisForm.Controls
thisControl.BackColor = System.Drawing.Color.LightBlue
Next thisControl
End Sub
En el ejemplo anterior se puede BackColor modificar el miembro de cada thisControl elemento, aunque no se puede modificar thisControl a sí mismo.
Recorrer matrices. Dado que Array la clase implementa la interfaz , todas las IEnumerable matrices exponen el método GetEnumerator . Esto significa que puede recorrer en iteración una matriz con un For Each bucle Next ... . Sin embargo, solo puede leer los elementos de la matriz. No se pueden cambiar.
Ejemplo 1
En el ejemplo siguiente se enumeran todas las carpetas de C:\ mediante la DirectoryInfo clase .
Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
Debug.WriteLine(dir.Name)
Next
Ejemplo 2
En el ejemplo siguiente se muestra un procedimiento para ordenar una colección. En el ejemplo se ordenan las instancias de una Car clase que se almacenan en List<T> . La clase Car implementa la interfaz IComparable<T>, que requiere implementar el método CompareTo.
Cada llamada al CompareTo método realiza una comparación única que se usa para la ordenación. El código escrito por el usuario en el método CompareTo devuelve un valor para cada comparación del objeto actual con otro objeto. El valor devuelto es menor que cero si el objeto actual es menor que el otro objeto, mayor que cero si el objeto actual es mayor que el otro objeto y cero si son iguales. Esto permite definir en el código los criterios de mayor que, menor que e igual.
En el método ListCars, la instrucción cars.Sort() ordena la lista. Esta llamada al método Sort de List<T> hace que se llame automáticamente al método CompareTo para los objetos Car de 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