Compartir a través de


Para cada... Instrucción 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 Obligatorio en la instrucción For Each. Opcional en la Next instrucción . Variable. Se usa para recorrer en iteración los elementos de la colección.
datatype Opcional si Option Infer está activado (el valor predeterminado) o element ya está declarado; obligatorio si Option Infer está desactivado y element aún no está declarado. Tipo de datos de element.
group Obligatorio. Variable con un tipo que es un tipo de colección o Object. Hace referencia a la colección sobre la statements que se van a repetir.
statements Opcional. Una o varias instrucciones entre For Each y Next que se ejecutan en cada elemento de 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 Obligatorio. Finaliza la definición del For Each bucle.

Ejemplo sencillo

Use un For Eachbucle ...Next cuando desee repetir un conjunto de instrucciones para cada elemento de una colección o matriz.

Sugerencia

Un para... Next Statement funciona bien cuando se puede asociar cada iteración de un bucle con una variable de control y determinar los valores iniciales y finales de esa variable. Sin embargo, cuando se trata de una colección, el concepto de valores iniciales y finales no es significativo y no necesariamente sabe cuántos elementos tiene la colección. En este tipo de caso, un For Eachbucle ...Next suele ser una mejor opción.

En el ejemplo siguiente, ...For Each 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, consulte Colecciones y matrices.

Bucles anidados

Puede anidar bucles For Each si coloca 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 variable única element .

También puede anidar diferentes tipos de estructuras de control entre sí. Para obtener más información, vea Estructuras de control anidadas.

Exit For y Continue For

La instrucción Exit For hace que la ejecución salga de ...For Next y transfiere inmediatamente el control a la instrucción que hay después de la instrucción Next.

La Continue For instrucción transfiere el control inmediatamente a la siguiente iteración del bucle. Para obtener más información, vea Continue Statement.

En el ejemplo siguiente se muestra cómo usar las Continue For instrucciones y 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 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 dentro de bucles anidados For Each , Exit For hace que la ejecución salga del bucle más interno y transfiera el control al siguiente nivel superior de 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 iterando es innecesario o imposible. Esto puede deberse a un valor erróneo o a una solicitud de terminación.

  • Se detecta una excepción en un Try...Catch...Finally. Puede usar Exit For al final del Finally bloque.

  • 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 Exit For para escapar el bucle. Para más información, consulte Do...Loop (Instrucción).

Iteradores

Se usa un iterador para realizar una iteración personalizada en una colección. Un iterador puede ser una función o un Get descriptor de acceso. Usa una Yield instrucción para devolver cada elemento de la colección uno a uno.

Se llama a un iterador mediante una For Each...Next instrucción . Cada iteración del For Each bucle llama al iterador. Cuando se alcanza una Yield instrucción en el iterador, se devuelve la expresión de la Yield instrucción y se conserva la ubicación actual en el código. La ejecución se reinicia desde esa ubicación la próxima vez que se llame al iterador.

En el ejemplo siguiente se usa una función de iterador. La función de iterador tiene una Yield instrucción que está dentro de un for... Bucle siguiente . En el ListEvenNumbers método , cada iteración del cuerpo de la For Each instrucción crea una llamada a la función iterador, que continúa con la instrucción siguiente Yield .

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, consulte Iterators, Yield Statement e 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 element o group, estos cambios no afectan a la iteración del bucle.

Cuando todos los elementos de la colección se han asignado sucesivamente a element, el For Each bucle se detiene y el control pasa a la instrucción después de la Next instrucción .

Si Option Infer está activado (su valor predeterminado), el compilador de Visual Basic puede deducir el tipo de datos de element. Si está desactivado y element no se ha declarado fuera del bucle, debe declararlo en la For Each instrucción . Para declarar el tipo de datos de element explícitamente, use una As cláusula . A menos que el tipo de datos de elemento se defina fuera de la For Eachconstrucción ...Next , su ámbito es el cuerpo del bucle. Tenga en cuenta que no puede declarar element tanto fuera como dentro del bucle.

Opcionalmente, puede especificar element en la Next instrucción . Esto mejora la legibilidad del programa, especialmente si tiene bucles anidados For Each . Debe especificar la misma variable que la que aparece en la instrucción correspondiente For Each .

Es posible que quiera evitar cambiar el valor de dentro de element un bucle. Esto puede dificultar la lectura y depuración del código. Cambiar el valor de group no afecta a la colección ni a sus elementos, que se determinaron cuando se escribió por primera vez el bucle.

Cuando se anidan bucles, si se encuentra una Next instrucción de un nivel de anidamiento externo antes Next del de un nivel interno, el compilador indica un error. Sin embargo, el compilador solo puede detectar este error superpuesto si especifica element en cada Next instrucción.

Si el código depende de recorrer una colección en un orden determinado, un For Eachbucle ...Next no es la mejor opción, a menos que conozca las características del objeto enumerador que expone la 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 va a devolver en element, o que es el siguiente que se va a devolver después de un elemento determinado. Puede lograr resultados más confiables mediante una estructura de bucle diferente, como For...Next o Do...Loop.

El tiempo de ejecución debe poder convertir los elementos de en groupelement. La instrucción [Option Strict] controla si se permiten conversiones de ampliación y restricción (Option Strict está desactivada, su valor predeterminado) o si solo se permiten conversiones de ampliación (Option Strict está activada). Para obtener más información, consulte Conversión de restricción.

El tipo de datos de debe ser un tipo de group referencia que haga referencia a una colección o a una matriz que sea enumerable. Normalmente esto significa que group hace referencia a un objeto que implementa la IEnumerable interfaz del System.Collections espacio de nombres o la IEnumerable<T> interfaz del System.Collections.Generic espacio de nombres. System.Collections.IEnumerable define el GetEnumerator método , que devuelve un objeto enumerador para la colección. El objeto enumerador implementa la System.Collections.IEnumerator interfaz del System.Collections espacio de nombres y expone la Current propiedad y los Reset métodos y MoveNext . Visual Basic los usa para recorrer la colección.

conversiones de restricción

Cuando Option Strict se establece en On, las conversiones de restricción normalmente provocan errores del compilador. Sin embargo, en una For Each instrucción , las conversiones de los elementos de group en element se evalúan y se realizan en tiempo de ejecución, y se suprimen los errores del compilador causados por conversiones de restricción.

En el ejemplo siguiente, la asignación de m como valor inicial de n no se compila cuando Option Strict está activada porque la conversión de a Long es Integer una conversión de restricción. Sin embargo, en la For Each instrucción no se notifica ningún error del compilador, aunque la asignación para number requiere la misma conversión de Long a Integer. En la For Each instrucción que contiene un gran número, se produce un error en tiempo de ejecución cuando ToInteger se aplica al gran número.

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 ejecución de un For Eachbucle ...Next , Visual Basic comprueba que group hace referencia a un objeto de colección válido. Si no es así, produce una excepción. De lo contrario, llama al MoveNext método y a la Current propiedad del objeto enumerador para devolver el primer elemento. Si MoveNext indica que no hay ningún elemento siguiente, es decir, si la colección está vacía, el bucle se detiene y el For Each control pasa a la instrucción después de la Next instrucción . De lo contrario, Visual Basic establece element en el primer elemento y ejecuta el bloque de instrucciones.

Cada vez que Visual Basic encuentra la Next instrucción , vuelve a la For Each instrucción . De nuevo llama MoveNext a y Current para devolver el siguiente elemento y, de nuevo, ejecuta el bloque o detiene el bucle en función del resultado. Este proceso continúa hasta MoveNext que indica que no se encuentra ningún elemento siguiente o se encuentra una Exit For instrucción .

Modificar la colección. El objeto enumerador devuelto por GetEnumerator normalmente no permite cambiar la colección agregando, eliminando, reemplazando o reordenando ningún elemento. Si cambia la colección después de haber iniciado un For Eachbucle ...Next , el objeto enumerador deja de ser válido y el siguiente intento de acceder a un elemento produce una InvalidOperationException excepción.

Sin embargo, este bloqueo de modificación no viene determinado por Visual Basic, sino por la implementación de la IEnumerable interfaz. Es posible implementar IEnumerable de una 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 IEnumerable implementación en la colección que está usando.

Modificar elementos de colección. La Current propiedad del objeto enumerador es ReadOnly y devuelve una copia local de cada elemento de colección. Esto significa que no se pueden modificar los propios elementos en un For Eachbucle ...Next . Cualquier modificación que realice solo afecta a la copia local de Current y no se refleja 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 modificar thisControl .

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 modificar el BackColor miembro de cada thisControl elemento, aunque no se puede modificar thisControl .

Recorrido de matrices. Dado que la Array clase implementa la IEnumerable interfaz, todas las matrices exponen el GetEnumerator método . Esto significa que puede recorrer en iteración una matriz con un For Eachbucle ...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 del directorio 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 instancias de una Car clase que se almacenan en .List<T> La Car clase implementa la IComparable<T> interfaz , que requiere que se implemente el CompareTo método .

Cada llamada al CompareTo método realiza una única comparación que se usa para la ordenación. El código escrito por el usuario en el CompareTo método 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 ListCars método , la cars.Sort() instrucción ordena la lista. Esta llamada al método Sort de List<T> hace que el método CompareTo se invoque automáticamente para los objetos Car en el 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

Consulte también