Instrucciones de salto (Referencia de C#)
Las siguientes instrucciones transfieren el control sin condiciones:
- La instrucción
break
: termina la instrucción de iteración contenedora más próxima o la instrucciónswitch
. - La instrucción
continue
: inicia una nueva iteración de la instrucción de iteración contenedora más próxima. - La instrucción
return
: termina la ejecución de la función en la que aparece y devuelve el control al llamador. - La instrucción
goto
: transfiere el control a una instrucción marcada por una etiqueta.
Para obtener información sobre la instrucción throw
que genera una excepción y también transfiere el control sin condiciones, consulte throw.
Instrucción break
La instrucción break
termina la instrucción de iteración contenedora más próxima (es decir, los bucles for
, foreach
, while
o do
) o la instrucción switch
. La instrucción break
transfiere el control a la instrucción que hay a continuación de la instrucción finalizada, si existe.
int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (int number in numbers)
{
if (number == 3)
{
break;
}
Console.Write($"{number} ");
}
Console.WriteLine();
Console.WriteLine("End of the example.");
// Output:
// 0 1 2
// End of the example.
En los bucles anidados, la instrucción break
termina solo el bucle más interno que la contiene, como se muestra en el ejemplo siguiente:
for (int outer = 0; outer < 5; outer++)
{
for (int inner = 0; inner < 5; inner++)
{
if (inner > outer)
{
break;
}
Console.Write($"{inner} ");
}
Console.WriteLine();
}
// Output:
// 0
// 0 1
// 0 1 2
// 0 1 2 3
// 0 1 2 3 4
Cuando usa la instrucción switch
dentro de un bucle, una instrucción break
al final de una sección switch transfiere el control solo fuera de la instrucción switch
. El bucle que contiene la instrucción switch
no se ve afectado, como se muestra en el ejemplo siguiente:
double[] measurements = { -4, 5, 30, double.NaN };
foreach (double measurement in measurements)
{
switch (measurement)
{
case < 0.0:
Console.WriteLine($"Measured value is {measurement}; too low.");
break;
case > 15.0:
Console.WriteLine($"Measured value is {measurement}; too high.");
break;
case double.NaN:
Console.WriteLine("Failed measurement.");
break;
default:
Console.WriteLine($"Measured value is {measurement}.");
break;
}
}
// Output:
// Measured value is -4; too low.
// Measured value is 5.
// Measured value is 30; too high.
// Failed measurement.
Instrucción continue
La instrucción continue
inicia una nueva iteración de la instrucción de iteración contenedora más próxima (es decir, los bucles for
, foreach
, while
o do
), como se muestra en el ejemplo siguiente:
for (int i = 0; i < 5; i++)
{
Console.Write($"Iteration {i}: ");
if (i < 3)
{
Console.WriteLine("skip");
continue;
}
Console.WriteLine("done");
}
// Output:
// Iteration 0: skip
// Iteration 1: skip
// Iteration 2: skip
// Iteration 3: done
// Iteration 4: done
Instrucción return
La instrucción return
termina la ejecución de la función en la que aparece y devuelve el control y el resultado de la función, si existe, al llamador.
Si un miembro de función no calcula un valor, se usa la instrucción return
sin expresión, como se muestra en el ejemplo siguiente:
Console.WriteLine("First call:");
DisplayIfNecessary(6);
Console.WriteLine("Second call:");
DisplayIfNecessary(5);
void DisplayIfNecessary(int number)
{
if (number % 2 == 0)
{
return;
}
Console.WriteLine(number);
}
// Output:
// First call:
// Second call:
// 5
Como se muestra en el ejemplo anterior, normalmente se usa la instrucción return
sin expresión para terminar un miembro de función al principio. Si un miembro de función no contiene la instrucción return
, termina después de ejecutarse su última instrucción.
Si un miembro de función calcula un valor, se usa la instrucción return
con una expresión, como se muestra en el ejemplo siguiente:
double surfaceArea = CalculateCylinderSurfaceArea(1, 1);
Console.WriteLine($"{surfaceArea:F2}"); // output: 12.57
double CalculateCylinderSurfaceArea(double baseRadius, double height)
{
double baseArea = Math.PI * baseRadius * baseRadius;
double sideArea = 2 * Math.PI * baseRadius * height;
return 2 * baseArea + sideArea;
}
Cuando la instrucción return
tiene una expresión, esa expresión debe poderse convertir implícitamente al tipo de valor devuelto de un miembro de función a menos que sea async. En el caso de una función async
, la expresión debe poderse convertir implícitamente al argumento de tipo de Task<TResult> o ValueTask<TResult>, el que sea el tipo de valor devuelto de la función. Si el tipo de valor devuelto de una función async
es Task o ValueTask, se usa la instrucción return
sin expresión.
De forma predeterminada, la instrucción return
devuelve el valor de una expresión. A partir de C# 7.0, puede devolver una referencia a una variable. Para ello, use la instrucción return
con la palabra clave ref
, como se muestra en el ejemplo siguiente:
var xs = new int[] { 10, 20, 30, 40 };
ref int found = ref FindFirst(xs, s => s == 30);
found = 0;
Console.WriteLine(string.Join(" ", xs)); // output: 10 20 0 40
ref int FindFirst(int[] numbers, Func<int, bool> predicate)
{
for (int i = 0; i < numbers.Length; i++)
{
if (predicate(numbers[i]))
{
return ref numbers[i];
}
}
throw new InvalidOperationException("No element satisfies the given condition.");
}
Para obtener más información sobre los valores devueltos de tipo red, consulte Valores devueltos y variables locales de tipo ref.
Instrucción goto
La instrucción goto
transfiere el control a una instrucción marcada por una etiqueta, como se muestra en el ejemplo siguiente:
var matrices = new Dictionary<string, int[][]>
{
["A"] = new[]
{
new[] { 1, 2, 3, 4 },
new[] { 4, 3, 2, 1 }
},
["B"] = new[]
{
new[] { 5, 6, 7, 8 },
new[] { 8, 7, 6, 5 }
},
};
CheckMatrices(matrices, 4);
void CheckMatrices(Dictionary<string, int[][]> matrixLookup, int target)
{
foreach (var (key, matrix) in matrixLookup)
{
for (int row = 0; row < matrix.Length; row++)
{
for (int col = 0; col < matrix[row].Length; col++)
{
if (matrix[row][col] == target)
{
goto Found;
}
}
}
Console.WriteLine($"Not found {target} in matrix {key}.");
continue;
Found:
Console.WriteLine($"Found {target} in matrix {key}.");
}
}
// Output:
// Found 4 in matrix A.
// Not found 4 in matrix B.
Como se muestra en el ejemplo anterior, se puede usar la instrucción goto
para salir de un bucle anidado.
Sugerencia
Cuando trabaje con bucles anidados, considere la posibilidad de refactorizar bucles independientes en métodos independientes. Eso puede dar lugar a un código más sencillo y legible sin la instrucción goto
.
También puede usar la instrucción goto
en la instrucción switch
para transferir el control a una sección switch con una etiqueta case constante, como se muestra en el ejemplo siguiente:
using System;
public enum CoffeChoice
{
Plain,
WithMilk,
WithIceCream,
}
public class GotoInSwitchExample
{
public static void Main()
{
Console.WriteLine(CalculatePrice(CoffeChoice.Plain)); // output: 10.0
Console.WriteLine(CalculatePrice(CoffeChoice.WithMilk)); // output: 15.0
Console.WriteLine(CalculatePrice(CoffeChoice.WithIceCream)); // output: 17.0
}
private static decimal CalculatePrice(CoffeChoice choice)
{
decimal price = 0;
switch (choice)
{
case CoffeChoice.Plain:
price += 10.0m;
break;
case CoffeChoice.WithMilk:
price += 5.0m;
goto case CoffeChoice.Plain;
case CoffeChoice.WithIceCream:
price += 7.0m;
goto case CoffeChoice.Plain;
}
return price;
}
}
Dentro de la instrucción switch
, también se puede usar la instrucción goto default;
para transferir el control a la sección switch con la etiqueta default
.
Si una etiqueta con el nombre especificado no existe en el miembro de función actual o si la instrucción goto
no está dentro del ámbito de la etiqueta, se produce un error en tiempo de compilación. Es decir, no se puede usar la instrucción goto
para transferir el control fuera del miembro de función actual o a cualquier ámbito anidado, por ejemplo, un bloque try
.
Especificación del lenguaje C#
Para más información, vea las secciones siguientes de la Especificación del lenguaje C#: