总目录
前言
介绍 C#中的break
、continue
、return
和 goto
四种跳转语句。
一、概述
- 跳转语句无条件转移控制。
- break 语句将终止最接近的封闭迭代语句或 switch 语句。
- continue 语句启动最接近的封闭迭代语句的新迭代。
- return 语句终止它所在的函数的执行,并将控制权返回给调用方。
- goto 语句将控制权转交给带有标签的语句。
迭代语句:使用 for、foreach、do 和 while 的语句
二、break 语句(中断语句)
1. 介绍
- break 语句:将终止最接近的封闭迭代语句(即 for、foreach、while 或 do 循环)或 switch 语句。
- break 语句将控制权转交给已终止语句后面的语句(若有)。
简单说: 在loop 中使用 break 将跳出整个循环,在switch 中使用break 将跳出switch 语句 ,然后执行后面的业务逻辑
2. 使用
static void Main(string[] args)
{
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.
}
上例中,当number == 3
的时候 就使用break 跳出了循环,因此只会输出0 1 2
static void Main(string[] args)
{
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
}
上例中,使用了双层for 的嵌套循环。在嵌套循环中,break 语句仅终止包含它的最内部循环。
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.
上例中,在循环内使用 switch 语句时,switch 节末尾的 break 语句仅从 switch 语句中转移控制权。 包含 switch 语句的循环不受影响
二、continue 语句(继续语句)
1. 介绍
- continue 语句启动最接近的封闭迭代语句(即 for、foreach、while 或 do 循环)的新迭代
简单说:跳出本轮循环,开始下一轮循环
2. 使用
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
三、return 语句(返回语句)
1. 介绍
- return 语句终止它所在的函数的执行,并将控制权和函数结果(若有)返回给调用方。
简单说:方法中使用 return,第一先终止执行(不再执行后面的代码),有返回值则返回 返回值,没有返回值,作用仅为终止执行
2. 使用
如果函数成员不计算值,则使用不带表达式的 return 语句
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
使用带表达式的 return 语句
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;
}
如果 return 语句具有表达式,该表达式必须可隐式转换为函数成员的返回类型,除非它是异步的。 从 async 函数返回的表达式必须隐式转换为 Task<TResult> 或 ValueTask<TResult> 类型参数,以函数的返回类型为准。 如果 async 函数的返回类型为 Task 或 ValueTask,则使用不带表达式的 return 语句。
三、goto 语句
1. 介绍
goto
语句将控制权转交给带有标签的语句- 使用
goto
,可以跳出 嵌套循环
简单说:代码跳转到 带有标签的地方 开始执行
2. 使用
- 下面案例中,定义了一个
Found:
标签,然后使用goto
跳转到Found
标签处
var matrices = new Dictionary<string, int[][]>
{
["A"] =
[
[1, 2, 3, 4],
[4, 3, 2, 1]
],
["B"] =
[
[5, 6, 7, 8],
[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.
- 还可使用 switch 语句中的 goto 语句将控制权移交到具有常量大小写标签的 switch 节,如以下示例所示:
public enum CoffeeChoice
{
Plain,
WithMilk,
WithIceCream,
}
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine(CalculatePrice(CoffeeChoice.Plain)); // output: 10.0
Console.WriteLine(CalculatePrice(CoffeeChoice.WithMilk)); // output: 15.0
Console.WriteLine(CalculatePrice(CoffeeChoice.WithIceCream)); // output: 17.0
}
private static decimal CalculatePrice(CoffeeChoice choice)
{
decimal price = 0;
switch (choice)
{
case CoffeeChoice.Plain:
price += 10.0m;
break;
case CoffeeChoice.WithMilk:
price += 5.0m;
goto case CoffeeChoice.Plain;
case CoffeeChoice.WithIceCream:
price += 7.0m;
goto case CoffeeChoice.Plain;
}
return price;
}
}
在 switch 语句中,还可使用语句 goto default
; 将控制权转交给带 default 标签的 switch 节。
3. 注意事项
-
可读性:goto语句会使代码流程难以追踪,特别是在复杂的代码结构中。因此,尽量避免使用goto,改用循环和条件语句来管理代码流程。
-
避免嵌套:尽量避免在深层嵌套的代码块中使用goto,因为这会使代码更加混乱和难以调试。
-
避免跳转到循环或条件语句内:通常不建议将goto语句用于跳转到循环或条件语句内部,因为这可能会导致不可预测的行为。
-
作用域问题:goto语句不能跨方法或块作用域跳转。它只能在当前方法或块内跳转。
-
结构化编程:尽量使用结构化编程技术(如循环、条件语句、方法调用等)来替代goto,以保持代码的可读性和可维护性。
-
替代方案
- 循环和条件语句:使用for、while、if-else等控制结构来替代goto。
- 方法调用:将复杂的逻辑拆分成多个方法,通过方法调用来控制流程。
- 异常处理:在需要跳出多层嵌套结构时,可以考虑使用异常处理机制(虽然这也不是最佳实践,但在某些情况下可能是可行的)。
四、跳转语句与try语句
- 跳转语句的执行因存在干预 try 语句而变得复杂。
- 在没有 try的情况下,跳转语句无条件地将控制权从跳转语句转移到其目标。
- 在存在此类干预 try 语句的情况下,执行更为复杂。
- 如果 jump 语句退出一个或多个 try 具有关联 finally 块的块,则控件最初将传输到 finally 最 try 内部语句的块。 当控件到达块的 finally 终点时,控件将 finally 传输到下一个封闭 try 语句的块。 此过程将重复执行, finally 直到执行所有干预 try 语句的块。
class Test
{
static void Main()
{
while (true)
{
try
{
try
{
Console.WriteLine("Before break");
break;
}
finally
{
Console.WriteLine("Innermost finally block");
}
}
finally
{
Console.WriteLine("Outermost finally block");
}
}
Console.WriteLine("After break");
}
}
Before break
Innermost finally block
Outermost finally block
After break
结语
回到目录页:C# 知识汇总
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。