Instrucciones de salto (Referencia de C#)

Las siguientes instrucciones transfieren el control sin condiciones:

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#:

Vea también