Instrucción For Each...Next (Visual Basic)

Actualización: Julio de 2008

Repite un grupo de instrucciones para cada elemento de una colección.

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

Partes

  • element
    Se requiere en la instrucción For Each. Es opcional en la instrucción Next. Variable. Se utiliza para recorrer en iteración los elementos de la colección.

  • datatype
    Es obligatorio, a menos que element no se haya declarado ya. Tipo de datos de element.

  • group
    Obligatorio. Variable de objeto. Hace referencia a la colección sobre la que se debe repetir la ejecución de statements.

  • statements
    Opcional. Una o más instrucciones entre For Each y Next que se ejecutan en cada elemento de group.

  • Exit For
    Opcional. Transfiere el control fuera del bucle For Each.

  • Next
    Obligatorio. Termina la definición del bucle For Each.

Comentarios

Utilice un bucle For Each...Next cuando desee repetir un conjunto de instrucciones para cada elemento de una colección o matriz.

Una Instrucción For...Next (Visual Basic) 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 colecciones, el concepto de valores iniciales y finales no es significativo, y no siempre se sabe cuántos elementos tiene la colección. En este caso, el bucle For Each...Next es la mejor opción.

Reglas

  • Tipos de datos. El tipo de datos de element debe ser tal que el tipo de datos de los elementos de group se pueda convertir en él.

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

    Los elementos de group normalmente son del tipo Object pero pueden tener cualquier tipo de datos en tiempo de ejecución.

  • Conversiones de restricción. Cuando Option Strict está establecido en On, las conversión de restricción suelen producir errores del compilador. En el ejemplo siguiente, la asignación de m como valor inicial de n no se compila con Option Strict porque la conversión de Long a Integer es una conversión de restricción.

    Dim m As Long = 987
    ' Does not compile.
    'Dim n As Integer = m
    

    Sin embargo, las conversiones de los elementos de group a element se evalúan y se realizan en tiempo de ejecución, por lo que se suprime el error de la conversión de restricción. En el ejemplo siguiente, no se notifica ningún error del compilador en el bucle For Each, aunque requiere la misma conversión de Long a Integer que produjo un error en el ejemplo anterior.

    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. The output is 45 3 987.
            For Each p As Integer In New Long() {45, 3, 987}
                Console.Write(p & " ")
            Next
            Console.WriteLine()
        End Sub
    End Module
    
    

    El hecho de que no se produzca un error del compilador no elimina el riesgo de un error en tiempo de ejecución. En el ejemplo siguiente, no se notifica ningún error del compilador, pero se produce un error en tiempo de ejecución cuando se aplica ToInteger a 9876543210. El error en tiempo de ejecución se produce tanto si Option Strict está activado como desactivado.

    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 = 9876543210
            'Dim n As Integer = m
    
            Try
                ' The For Each loop requires the same conversion, but
                ' is not flagged by the compiler. A run-time error is 
                ' raised because 9876543210 is too large for type Integer.
                For Each p As Integer In New Long() {45, 3, 9876543210}
                    Console.Write(p & " ")
                Next
                Console.WriteLine()
            Catch e As System.OverflowException
                Console.WriteLine()
                Console.WriteLine(e.Message)
            End Try
        End Sub
    End Module
    
    
  • Declaración. Si element no se ha declarado fuera de este bucle, se debe declarar en la instrucción For Each. Puede declarar el tipo de element explícitamente mediante una instrucción As o bien puede basarse en la inferencia de tipos para asignar el tipo. En ambos casos, el ámbito de element es el cuerpo del bucle. Sin embargo, no se puede declarar element fuera y dentro del bucle.

  • Número de iteraciones. Visual Basic sólo evalúa una vez la colección, antes de que comience el bucle. Si el bloque de instrucciones cambia element o group, estos cambios no afectan a la iteración del bucle.

  • Bucles anidados. Se pueden anidar bucles For Each colocando un bucle dentro de otro. Sin embargo, cada bucle debe tener una variable element única.

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

    Nota:

    Si una instrucción Next de un nivel de anidamiento externo se encuentra antes de la instrucción Next de un nivel interno, el compilador genera un error. Sin embargo, el compilador sólo puede detectar este error superpuesto si se especifica element en cada instrucción Next.

  • Identificar la variable de control. Opcionalmente, puede especificarse element en la instrucción Next. Esto mejora la legibilidad del programa, sobre todo si se han anidado bucles For Each. La variable que se especifique debe ser igual a la que aparece en la instrucción For Each correspondiente.

  • Transferir fuera del bucle. La Instrucción Exit (Visual Basic) transfiere el control inmediatamente a la instrucción que sigue a Next. Por ejemplo, puede ser conveniente salir de un bucle si se detecta una condición que hace que sea innecesario o imposible continuar la iteración, como puede ser un valor erróneo o una solicitud de finalización. Asimismo, si se detecta una excepción en una instrucción Try...Catch...Finally, se puede utilizar Exit For al final del bloque Finally.

    Se puede colocar cualquier número de instrucciones Exit For en un bucle For Each. Exit For se suele utilizar después de evaluar alguna condición, por ejemplo en una estructura If...Then...Else.

  • Bucles sin fin. Un uso de Exit For es comprobar una condición que pudiera ocasionar un bucle sin fin; es decir, un bucle que pudiera ejecutarse un número extremadamente elevado de veces e incluso infinitamente. Si se detecta este tipo de condición, se puede utilizar Exit For para escapar del bucle. Para obtener más información, vea Instrucción Do...Loop (Visual Basic).

Comportamiento

  • Entrada en el bucle. Cuando comienza la ejecución del bucle For Each...Next, Visual Basic comprueba que group hace referencia a un objeto de colección válido. Si no, produce una excepción. De lo contrario, llama al método MoveNext y a la propiedad Current del objeto enumerador para devolver el primer elemento. Si MoveNext indica que no hay un elemento siguiente, es decir, si la colección está vacía, el bucle For Each termina y el control pasa a la instrucción que sigue a Next. De lo contrario, Visual Basic establece element en el primer elemento y ejecuta el bloque de instrucciones.

  • Iteraciones del bucle. Cada vez que Visual Basic encuentra la instrucción Next, vuelve a la instrucción For Each. Llama de nuevo a MoveNext y Current para devolver el elemento siguiente, y una vez más ejecuta el bloque o termina el bucle según el resultado. Este proceso continúa hasta que MoveNext indica que no hay ningún elemento siguiente o se encuentra una instrucción Exit For.

  • Terminación del bucle. Cuando todos los elementos de la colección se han asignado correctamente a element, el bucle For Each termina y el control pasa a la instrucción que sigue a Next.

  • Cambiar los valores de iteración. Cambiar el valor de element mientras se está dentro de un bucle puede dificultar la lectura y la depuración del código. Cambiar el valor de group no afecta a la colección o sus elementos, que se determinaron en el momento de entrar en el bucle.

  • Orden de recorrido. Cuando se ejecuta un bucle For Each...Next, el recorrido de la colección está bajo el control del objeto enumerador devuelto por el método GetEnumerator. El orden de recorrido no lo determina Visual Basic, sino el método MoveNext del objeto enumerador. Esto significa que tal vez no se pueda predecir qué elemento de la colección es el primero que se devuelve en element o qué elemento es el siguiente en ser devuelto tras un elemento dado.

    Si el código utilizado depende del recorrido de una colección en un orden concreto, un bucle For Each...Next no es la mejor opción a menos que conozca las características del objeto enumerador que expone la colección. Es posible obtener resultados más fiables si se utiliza una estructura de bucle diferente, tal como For...Next o Do...Loop.

  • Modificar la colección. El objeto enumerador devuelto por GetEnumerator normalmente no permite que se agreguen, eliminen, reemplacen o reordenen elementos de la colección. Si se modifica la colección después de haber iniciado un bucle For Each...Next, el objeto enumerador deja de ser válido y el siguiente intento de acceso a un elemento produce una excepción InvalidOperationException.

    Sin embargo, este bloqueo de la modificación no viene determinado por Visual Basic sino por la implementación de la interfaz IEnumerable. Es posible implementar IEnumerable de modo que se permita la modificación durante la iteración. Si piensa realizar este tipo de modificación dinámica, asegúrese de conocer las características de la implementación de IEnumerable en la colección que está utilizando.

  • Modificar los elementos de colección. La propiedad Current del objeto enumerador es ReadOnly (Visual Basic) y devuelve una copia local de cada elemento de la colección. Esto significa que no es posible modificar los propios elementos en un bucle For Each...Next. Cualquier modificación que se realice afectará sólo a la copia local de Current y no se verá reflejada de nuevo en la colección subyacente. Sin embargo, si un elemento es un tipo de referencia, es posible modificar los miembros de la instancia a los que apunta. Esto se ilustra en el siguiente ejemplo:

    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
    

    En el ejemplo anterior se puede modificar el miembro BackColor de cada elemento thisControl, aunque no se puede modificar el propio elemento thisControl.

  • Recorrer matrices. Dado que la clase Array implementa la interfaz IEnumerable, todas las matrices exponen el método GetEnumerator. Esto significa que es posible recorrer una matriz con un bucle For Each...Next. Sin embargo, sólo podrá leer los elementos de la matriz, no modificarlos. Para obtener un ejemplo, vea Cómo: Ejecutar varias instrucciones para todos los elementos de una colección o matriz.

Ejemplo

En el ejemplo siguiente se utiliza la instrucción For Each...Next para buscar todos los elementos en una colección de la cadena "Hello". El ejemplo supone que ya se ha creado la colección thisCollection y que sus elementos son de tipo String.

Dim found As Boolean = False
Dim thisCollection As New Collection
For Each thisObject As String In thisCollection
    If thisObject = "Hello" Then
        found = True
        Exit For
    End If
Next thisObject

Vea también

Tareas

Cómo: Ejecutar varias instrucciones para todos los elementos de una colección o matriz

Cómo: Mejorar el rendimiento de un bucle

Conceptos

Estructuras de bucles

Colecciones en Visual Basic

Conversiones de ampliación y de restricción

Referencia

Instrucción While...End While (Visual Basic)

Instrucción Do...Loop (Visual Basic)

Historial de cambios

Fecha

Historial

Motivo

Julio de 2008

Se ha agregado una sección sobre las conversiones de restricción.

Comentarios de los clientes.