break termina un bucle antes de tiempo. continue se salta el resto de la iteración actual y pasa a la siguiente. Los dos se aplican al bucle más interno que los contiene, y funcionan igual en for, foreach, while y do while.
Salida:
process order of 45
skip invalid total 0
process order of 120
skip invalid total -5
process order of 80
test order found, stopping
after the loop
continue saltó por encima de la línea de procesamiento para 0 y -5. break detuvo el bucle en 999, así que 60 nunca se visitó, y la ejecución continuó en la primera sentencia después del bucle.
break: parar cuando ya se conoce la respuesta
El uso típico de break es una búsqueda: en cuanto has encontrado lo que buscabas, no hay motivo para mirar el resto.
Salida:
first invalid email at index 1
El iterador (i++) no se ejecuta después de un break, así que i seguiría conteniendo el índice encontrado si estuviera declarada fuera del bucle. En búsquedas sencillas, una llamada de biblioteca dice lo mismo: Array.FindIndex(emails, e => !e.Contains("@")) devuelve el índice (o -1), y emails.Any(e => !e.Contains("@")) de LINQ responde si existe uno incorrecto.
continue: saltar a la siguiente iteración
continue es una cláusula de guarda para bucles. En lugar de envolver el trabajo real en un if, rechaza al principio los casos que no quieres:
Salida:
pen costs 1.20
mug costs 8.00
Adónde va continue depende del bucle. En un bucle for ejecuta el iterador y después prueba la condición. En un bucle while salta directamente a la condición, lo que lleva a un bug clásico:
int i = 0;
while (i < 10)
{
if (i % 2 == 0)
continue; // i++ below is skipped: i stays 0 forever
Console.WriteLine(i);
i++;
}
Actualiza el contador antes de cualquier continue, o usa un bucle for, donde la actualización vive en la cabecera y siempre se ejecuta.
break dentro de un switch dentro de un bucle
En un switch, break termina la sección del case. Cuando ese switch está en un bucle, el break pertenece al switch, no al bucle:
Salida:
quit received
count = 2
Un break normal en el case "quit" habría terminado solo el switch, el bucle habría seguido y count valdría 3. El goto salta a la etiqueta situada después del bucle. Mover el bucle a un método y escribir return en ese case también funciona y no necesita etiqueta.
Salir de bucles anidados
C# no tiene break con etiqueta como el break outer; de Java. Cuando una búsqueda recorre dos bucles anidados, un break en el bucle interior solo termina el interior; el bucle exterior pasa a su fila siguiente. Hay tres soluciones habituales.
1. Una variable indicadora que comprueba el bucle exterior:
Salida:
first free seat: row 1, seat 2
2. goto a una etiqueta situada después de los dos bucles. Es el único sitio donde muchas guías de estilo de C# aceptan goto, porque expresa exactamente "sal de los dos bucles":
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
if (seats[row, col] == 0)
{
Console.WriteLine($"first free seat: row {row}, seat {col}");
goto done;
}
}
}
done:
Console.WriteLine("search finished");
3. Un método con return, normalmente lo más limpio, porque la búsqueda recibe un nombre y puede devolver su resultado:
Salida:
first free seat: row 1, seat 2
C# 7.0 también introdujo las funciones locales, que te permiten poner ese método auxiliar dentro del método que lo llama. El patrón con parámetro out que se usa aquí se explica en la página de ref y out.
goto y etiquetas
Una etiqueta es un identificador seguido de dos puntos, y goto label; salta a ella. Las reglas son lo bastante estrictas como para evitar el peor abuso:
- La etiqueta debe estar en el mismo método, en el mismo bloque que el
gotoo en uno que lo contenga. Puedes saltar fuera de los bloques pero nunca dentro de uno: saltar desde fuera a una etiqueta dentro del cuerpo de un bucle es el error CS0159 (no existe esa etiqueta en el ámbito de la sentencia goto). - No puedes salir de un bloque
finallycongoto,breaknicontinue. - Dentro de un
switch,goto case 3;ygoto default;transfieren el control a otra sección. Así es como un switch de C# expresa el paso de un case a otro, ya que caer al case siguiente de forma implícita es un error de compilación.
goto también puede construir bucles (saltando hacia atrás a una etiqueta), pero un bucle while dice lo mismo de una forma que todo lector reconoce. Reserva goto para salir de bucles anidados y para las secciones de un switch.
return, throw y los bucles
return sale del método entero, así que también sale de todos los bucles que contiene. throw hace lo mismo lanzando una excepción. Dentro de un bloque try con finally, break, continue, goto y return siguen ejecutando el bloque finally antes de que el control avance, y eso es lo que hace seguro salir de un bucle que tiene un archivo abierto en un bloque using.
| Sentencia | Sale de | Continúa en |
|---|---|---|
continue | la iteración actual | la siguiente iteración (iterador y después condición) |
break | el bucle o switch más interno | la sentencia que va después |
goto label | cualquier bloque que lo contenga | la etiqueta |
return | el método | quien lo llamó |
throw | todo hasta un catch que coincida | el bloque catch |
Preguntas frecuentes
¿Qué diferencia hay entre break y continue en C#?
break termina de inmediato el bucle más interno (o el switch); la ejecución sigue después de él. continue termina solo la iteración actual y salta a la siguiente: en un bucle for se ejecuta después el iterador, en while y do while se prueba después la condición, en foreach se obtiene el siguiente elemento.
¿Cómo salgo de bucles anidados en C#?
C# no tiene break con etiqueta. Las tres opciones son: activar una variable bool indicadora y probarla en el bucle exterior, saltar más allá de los dos bucles con goto a una etiqueta, o mover los bucles a un método y hacer return desde él. La versión con método suele ser la más limpia, porque además da a la búsqueda un nombre y un valor de retorno.
¿Sale del bucle un break dentro de un switch en C#?
No. Dentro de un switch que está en un bucle, break termina la sección del switch y el bucle sigue. Para salir del bucle desde dentro de un case, usa return, una variable indicadora comprobada después del switch, o goto a una etiqueta situada después del bucle. continue dentro de un case sí va a la siguiente iteración del bucle.
¿Está permitido goto en C#?
Sí. goto label; salta a label: en el mismo método, pero no puede saltar dentro de un bloque ni fuera de un finally. Dentro de un switch, goto case value; y goto default; saltan entre secciones. Fuera de salir de bucles anidados y del paso explícito entre cases de un switch, goto rara vez es la opción más clara.