Instrucciones de iteración (referencia de C#)

Las siguientes instrucciones ejecutan repetidamente una instrucción o un bloque de instrucciones:

  • La instrucción for: ejecuta su cuerpo mientras una expresión booleana especificada se evalúe como true.
  • La instrucción foreach: enumera los elementos de una colección y ejecuta su cuerpo para cada elemento de la colección.
  • La instrucción do: ejecuta condicionalmente su cuerpo una o varias veces.
  • La instrucción while: ejecuta condicionalmente su cuerpo cero o varias veces.

En cualquier punto del cuerpo de una instrucción de iteración, se puede salir del bucle mediante la instrucción break, o bien se puede ir a la siguiente iteración del bucle mediante la instrucción continue.

Instrucción for

La instrucción for ejecuta una instrucción o un bloque de instrucciones mientras una expresión booleana especificada se evalúa como true. En el ejemplo siguiente se muestra la instrucción for, que ejecuta su cuerpo mientras que un contador entero sea menor que tres:

for (int i = 0; i < 3; i++)
{
    Console.Write(i);
}
// Output:
// 012

En el ejemplo anterior se muestran los elementos de la instrucción for:

  • La sección inicializador, que se ejecuta solo una vez, antes de entrar en el bucle. Normalmente, se declara e inicializa una variable de bucle local en esa sección. No se puede acceder a la variable declarada desde fuera de la instrucción for.

    La sección inicializador del ejemplo anterior declara e inicializa una variable de contador entero:

    int i = 0
    
  • La sección condición que determina si se debe ejecutar la siguiente iteración del bucle. Si se evalúa como true o no está presente, se ejecuta la siguiente iteración; de lo contrario, se sale del bucle. La sección condición debe ser una expresión booleana.

    La sección condición del ejemplo anterior comprueba si un valor de contador es menor que tres:

    i < 3
    
  • La sección iterador, que define lo que sucede después de cada iteración del cuerpo del bucle.

    La sección iterador del ejemplo anterior incrementa el contador:

    i++
    
  • El cuerpo del bucle, que es una instrucción o un bloque de instrucciones.

La sección iterador puede contener cero o más de las siguientes expresiones de instrucción, separadas por comas:

  • expresión de incremento de prefijo o sufijo, como ++i o i++
  • expresión de decremento de prefijo o sufijo, como --i o i--
  • asignación
  • invocación de un método
  • expresión await
  • creación de un objeto mediante el operador new

Si no declara una variable de bucle en la sección inicializador, también puede usar cero o varias de las expresiones de la lista anterior de dicha sección. En el ejemplo siguiente se muestran varios usos menos comunes de las secciones inicializador e iterador: asignar un valor a una variable externa en la sección inicializador, invocar un método en las secciones inicializador e iterador, y cambiar los valores de dos variables en la sección iterador:

int i;
int j = 3;
for (i = 0, Console.WriteLine($"Start: i={i}, j={j}"); i < j; i++, j--, Console.WriteLine($"Step: i={i}, j={j}"))
{
    //...
}
// Output:
// Start: i=0, j=3
// Step: i=1, j=2
// Step: i=2, j=1

Todas las secciones de la instrucción for son opcionales. En el ejemplo, el siguiente código define el bucle for infinito:

for ( ; ; )
{
    //...
}

Instrucción foreach

La instrucción foreach ejecuta una instrucción o un bloque de instrucciones para cada elemento de una instancia del tipo que implementa la interfaz System.Collections.IEnumerable o System.Collections.Generic.IEnumerable<T>, como se muestra en el siguiente ejemplo:

var fibNumbers = new List<int> { 0, 1, 1, 2, 3, 5, 8, 13 };
foreach (int element in fibNumbers)
{
    Console.Write($"{element} ");
}
// Output:
// 0 1 1 2 3 5 8 13

La instrucción foreach no está limitada a esos tipos. Puede usarla con una instancia de cualquier tipo que cumpla las condiciones siguientes:

  • Un tipo tiene el método público GetEnumerator sin parámetros. A partir de C# 9.0, el método GetEnumerator puede ser el método de extensión de un tipo.
  • El tipo de valor devuelto del método GetEnumerator tiene la propiedad pública Current y el método público MoveNext sin parámetros, cuyo tipo de valor devuelto es bool.

En el siguiente ejemplo se usa la instrucción foreach con una instancia del tipo System.Span<T>, que no implementa ninguna interfaz:

Span<int> numbers = new int[] { 3, 14, 15, 92, 6 };
foreach (int number in numbers)
{
    Console.Write($"{number} ");
}
// Output:
// 3 14 15 92 6

A partir de C# 7.3, si la propiedad Current del enumerador devuelve un valor devuelto de referencia (ref T donde T es el tipo de un elemento de colección), se puede declarar una variable de iteración con el modificador ref o ref readonly, como se muestra en el siguiente ejemplo:

Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
    item = num++;
}
foreach (ref readonly var item in storage)
{
    Console.Write($"{item} ");
}
// Output:
// 0 1 2 3 4 5 6 7 8 9

Si la instrucción foreach se aplica a null, se produce NullReferenceException. Si la colección de origen de la instrucción foreach está vacía, el cuerpo de la instrucción foreach no se ejecuta y se omite.

await foreach

A partir de C# 8.0, puede usar la instrucción await foreach para usar una secuencia de datos asincrónica, es decir, el tipo de colección que implementa la interfaz IAsyncEnumerable<T>. Cada iteración del bucle se puede suspender mientras el siguiente elemento se recupera de forma asincrónica. En el ejemplo siguiente se muestra cómo usar la instrucción await foreach:

await foreach (var item in GenerateSequenceAsync())
{
    Console.WriteLine(item);
}

También puede usar la instrucción await foreach con una instancia de cualquier tipo que cumpla las condiciones siguientes:

  • Un tipo tiene el método público GetAsyncEnumerator sin parámetros. Ese método puede ser el método de extensión del tipo.
  • El tipo de valor devuelto del método GetAsyncEnumerator tiene la propiedad pública Currenty el método público MoveNextAsync sin parámetros cuyo tipo de valor devuelto es Task<bool>, ValueTask<bool>, o cualquier otro tipo que se puede esperar cuyo método GetResult de awaiter devuelve un valor bool.

Los elementos de secuencia se procesan de forma predeterminada en el contexto capturado. Si quiere deshabilitar la captura del contexto, use el método de extensión TaskAsyncEnumerableExtensions.ConfigureAwait. Para obtener más información sobre los contextos de sincronización y la captura del contexto actual, vea Utilizar el modelo asincrónico basado en tareas. Para obtener más información sobre secuencias asincrónicas, vea la sección Secuencias asincrónicas del artículo Novedades de C# 8.0.

Tipo de una variable de iteración

Puede usar la palabra clave var para permitir que el compilador infiera el tipo de una variable de iteración de la instrucción foreach, como se muestra en el código siguiente:

foreach (var item in collection) { }

También puede especificar de forma explícita el tipo de una variable de iteración, como se muestra en el código siguiente:

IEnumerable<T> collection = new T[5];
foreach (V item in collection) { }

En el formulario anterior, el tipo T de un elemento de colección se debe poder convertir de forma implícita o explícita en el tipo V de una variable de iteración. Si se produce un error en una conversión explícita de T en V en tiempo de ejecución, la instrucción foreach produce InvalidCastException. Por ejemplo, si T es un tipo de clase no sellada, V puede ser cualquier tipo de interfaz, incluso uno que T no implemente. En tiempo de ejecución, el tipo de un elemento de colección puede ser el que deriva de T y realmente implementa V. Si ese no es el caso, se produce InvalidCastException.

Instrucción do

La instrucción do ejecuta una instrucción o un bloque de instrucciones mientras que una expresión booleana especificada se evalúa como true. Como esa expresión se evalúa después de cada ejecución del bucle, un bucle do se ejecuta una o varias veces. Esto es diferente de un bucle while, que se ejecuta cero o varias veces.

En el ejemplo siguiente se muestra el uso de la instrucción do:

int n = 0;
do
{
    Console.Write(n);
    n++;
} while (n < 5);
// Output:
// 01234

Instrucción while

La instrucción while ejecuta una instrucción o un bloque de instrucciones mientras que una expresión booleana especificada se evalúa como true. Como esa expresión se evalúa antes de cada ejecución del bucle, un bucle while se ejecuta cero o varias veces. Esto es diferente de un bucle do que se ejecuta una o varias veces.

En el ejemplo siguiente se muestra el uso de la instrucción while:

int n = 0;
while (n < 5)
{
    Console.Write(n);
    n++;
}
// Output:
// 01234

Especificación del lenguaje C#

Para más información, vea las secciones siguientes de la Especificación del lenguaje C#:

Para obtener más información sobre de las características agregadas en C# 8.0 y versiones posteriores, vea las siguientes notas de propuesta de características:

Vea también