Jump statements (C# reference)
The following statements unconditionally transfer control:
- The
break
statement: terminates the closest enclosing iteration statement orswitch
statement. - The
continue
statement: starts a new iteration of the closest enclosing iteration statement. - The
return
statement: terminates execution of the function in which it appears and returns control to the caller. - The
goto
statement: transfers control to a statement that is marked by a label.
For information about the throw
statement that throws an exception and unconditionally transfers control as well, see throw.
The break
statement
The break
statement terminates the closest enclosing iteration statement (that is, for
, foreach
, while
, or do
loop) or switch
statement. The break
statement transfers control to the statement that follows the terminated statement, if any.
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.
In nested loops, the break
statement terminates only the innermost loop that contains it, as the following example shows:
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
When you use the switch
statement inside a loop, a break
statement at the end of a switch section transfers control only out of the switch
statement. The loop that contains the switch
statement is unaffected, as the following example shows:
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.
The continue
statement
The continue
statement starts a new iteration of the closest enclosing iteration statement (that is, for
, foreach
, while
, or do
loop), as the following example shows:
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
The return
statement
The return
statement terminates execution of the function in which it appears and returns control and the function's result, if any, to the caller.
If a function member doesn't compute a value, you use the return
statement without expression, as the following example shows:
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
As the preceding example shows, you typically use the return
statement without expression to terminate a function member early. If a function member doesn't contain the return
statement, it terminates after its last statement is executed.
If a function member computes a value, you use the return
statement with an expression, as the following example shows:
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;
}
When the return
statement has an expression, that expression must be implicitly convertible to the return type of a function member unless it's async. In the case of an async
function, the expression must be implicitly convertible to the type argument of Task<TResult> or ValueTask<TResult>, whichever is the return type of the function. If the return type of an async
function is Task or ValueTask, you use the return
statement without expression.
By default, the return
statement returns the value of an expression. Beginning with C# 7.0, you can return a reference to a variable. To do that, use the return
statement with the ref
keyword, as the following example shows:
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.");
}
For more information about ref returns, see Ref returns and ref locals.
The goto
statement
The goto
statement transfers control to a statement that is marked by a label, as the following example shows:
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.
As the preceding example shows, you can use the goto
statement to get out of a nested loop.
Tip
When you work with nested loops, consider refactoring separate loops into separate methods. That may lead to a simpler, more readable code without the goto
statement.
You can also use the goto
statement in the switch
statement to transfer control to a switch section with a constant case label, as the following example shows:
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;
}
}
Within the switch
statement, you can also use the statement goto default;
to transfer control to the switch section with the default
label.
If a label with the given name doesn't exist in the current function member, or if the goto
statement is not within the scope of the label, a compile-time error occurs. That is, you can't use the goto
statement to transfer control out of the current function member or into any nested scope, for example, a try
block.
C# language specification
For more information, see the following sections of the C# language specification:
See also
Feedback
Submit and view feedback for