文章目录
- 基本语法
- 示例
- 注意
- 使用goto
- 跳转其他标签
基本语法
switch语句是一种选择结构,用于基于某个表达式的值执行不同的代码块。它提供了一种更简洁、更易读的方式来处理多路分支逻辑,相比于多个嵌套的if…else if…else语句。下面是switch语句的基本语法和用法说明:
switch (expression)
{
case constantExpression1:
// 执行的代码块1
break;
case constantExpression2:
// 执行的代码块2
break;
// ... 可以有更多case语句
default:
// 如果没有匹配的case,执行这里的代码块(可选)
break;
}
expression
: 这是一个要评估的表达式,其结果会与各个case标签后的常量表达式进行比较。
constantExpression1, constantExpression2, ...
: 这些是与expression结果比较的常量值。
switch语句的测试限于离散的值。
离散的值,指的是在一个集合或数列中,各数值之间彼此独立,不存在介于两者之间的其他可能值,这样的值我们称之为离散值。换句话说,离散值不构成连续的序列,它们是可数的,且是彼此分离的,没有无限细分的可能。
比如说,骰子掷出的点数,当掷一个标准的六面骰子时,可能的结果是1、2、3、4、5、6,这些都是离散的值,因为不存在介于这些整数之间的结果。
或者学生的班级排名,比如在一个班级里,学生按照成绩排名,第1名、第2名、……直到第n名,这些排名是离散的,你不能有“第1.5名”。
又或者足球比赛的进球数,一场足球比赛结束时,一支队伍可能进0球、1球、2球等,这些进球数是明确可数的,不存在0.5个进球这样的情况。
这意味着它只能用来比较表达式的值是否与预定义的一系列具体的值相等。这些值可以是整数、字符、枚举值,或者在C# 7.0及以后版本中,case标签也可以是字符串、元组、以及使用when子句进行更复杂的条件检查。模式匹配功能允许更复杂的模式,包括类型模式和属性模式等。这让switch能够处理更广泛的情况,但核心上仍然是基于离散值或明确的匹配条件来进行判断。
注意,仅限于离散值,也就是说你不能直接用switch来测试一个范围内的值(比如年龄是否在18到65之间),或者浮点数的精确相等(因为浮点运算可能存在误差),而是需要将这类连续的或非精确的比较转化为对离散值的检查,比如通过区间划分成具体的 case。
break
: 当匹配到一个case后,执行相应代码块,然后遇到break会跳出switch语句。如果不写break,则会继续执行下一个case,这称为“贯穿”(fall through)。default
: 这是一个可选的标签,表示如果没有case匹配到expression的结果时执行的代码块。
示例
int dayOfWeek = (int)DateTime.Now.DayOfWeek;
switch (dayOfWeek)
{
case 1:
Console.WriteLine("星期一");
break;
case 2:
Console.WriteLine("星期二");
break;
case 3:
Console.WriteLine("星期三");
break;
// ...
default:
Console.WriteLine("这是一个周末或其他未指定的日子");
break;
}
注意
每个case标签后面的代码块可以为空,但如果有执行语句,则通常需要跟随一个break来防止贯穿,如下所示。
int age=2;
switch (age)
{
case 1:
// 执行的代码块1
break;
case 2:
default:
// 如果没有匹配的case,执行这里的代码块(可选)
break;
}
default部分可以位于switch语句的任何位置,但习惯上放在最后。
使用goto
在C#中,switch语句主要用于基于不同的条件执行不同块的代码,而goto语句提供了一种无条件跳转的机制。虽然在C#中使用goto是合法的,但在switch语句内部使用它并不是典型的做法,因为C#提供了更结构化的控制流机制,如break、continue、以及模式匹配(在C# 7.0及以上版本中增强的switch语句)。
不过你还是可以在C#的switch语句外部使用goto来改变控制流程,包括跳过switch块或跳转到特定的代码段。但请注意,过度依赖goto可能会导致代码难以阅读和维护。
下面的C#示例展示了一个非常规的用法,其中goto用于在switch外部跳过部分代码块,但请注意这并非推荐的编码规范:
static void Main()
{
StartMenu:
Console.WriteLine("\n欢迎来到导航示例!");
Console.WriteLine("请选择一个选项:");
Console.WriteLine("1. 转到信息板块");
Console.WriteLine("2. 转到行动板块");
Console.WriteLine("3. 退出");
string input = Console.ReadLine();
if (!int.TryParse(input, out int choice) || choice < 1 || choice > 3)
{
Console.WriteLine("无效的选择。请重试。");
goto StartMenu; // 返回开始菜单
}
switch (choice)
{
case 1:
goto InformationSection;
case 2:
goto ActionSection;
case 3:
Console.WriteLine("正在退出程序。再见!");
return;
default:
// 这里实际上不会被执行,因为前面已经做了检查,但为了完整性保留
break;
}
InformationSection:
Console.WriteLine("\n--- 信息板块 ---");
Console.WriteLine("在这里您可以找到详细信息。");
Console.WriteLine("按任意键返回菜单。");
Console.ReadKey();
goto StartMenu; // 返回开始菜单
ActionSection:
Console.WriteLine("\n--- 行动板块 ---");
Console.WriteLine("在这里您可以执行操作。");
Console.WriteLine("按任意键返回菜单。");
Console.ReadKey();
goto StartMenu; // 返回开始菜单
}
跳转其他标签
int action = 1; // 示例中的动作选择
switch (action)
{
case 1:
Console.WriteLine("执行动作1的逻辑...");
goto case 2; // 从case 1跳转到case 2,不推荐的做法
case 2:
Console.WriteLine("执行动作2的逻辑...");
break;
case 3:
Console.WriteLine("执行动作3的逻辑...");
break;
default:
Console.WriteLine("未定义的动作。");
break;
}
在这个示例中,如果action
变量的值为1,程序会在执行完case 1的逻辑后,通过goto case 2;直接跳转到case 2继续执行,绕过了正常的流程控制。这种方式虽然可行,但降低了代码的清晰度和可维护性。通常,我们应当在每个case块末尾使用break来更清晰地控制程序的流程。