C# Switch 语句入门指南 – wiki基地


C# Switch 语句深度解析:从基础入门到高级应用指南 (附带实用示例)

欢迎来到 C# 编程世界!在编写程序时,我们经常需要根据不同的条件执行不同的代码块。最常见的工具是 if-else if-else 结构,它强大而灵活。然而,当需要根据一个变量的精确值在众多可能性中选择一个执行路径时,if-else if-else 可能会变得冗长且难以阅读。这时,C# 的 switch 语句就闪亮登场了。

switch 语句为我们提供了一种更清晰、更简洁的方式来处理基于单个表达式值的多重选择。它不仅提升了代码的可读性,在某些情况下,编译器还能对其进行优化,可能带来性能上的提升。

本文将带你深入了解 C# 中的 switch 语句,从最基础的语法和用法,到现代 C# 版本(如 C# 8.0 及更高版本)引入的强大新特性——switch 表达式和模式匹配。无论你是编程新手还是希望巩固基础知识的开发者,都能从中获益。

让我们开始这段 switch 语句的探索之旅吧!

第一部分:传统 Switch 语句的基础

1. 什么是 Switch 语句?

switch 语句是一种控制流语句,它允许程序根据一个表达式的值,在一系列可能的代码块中选择一个来执行。它非常适用于处理离散的、有限的值集合,例如整数、枚举成员、字符串或字符等。

想象一下这样的场景:你需要根据用户输入的数字(1 到 7)来打印对应是星期几。使用 if-else if,代码可能会是这样:

“`csharp
int dayOfWeek = GetUserInput(); // 假设获取到用户输入的数字

if (dayOfWeek == 1)
{
Console.WriteLine(“星期一”);
}
else if (dayOfWeek == 2)
{
Console.WriteLine(“星期二”);
}
else if (dayOfWeek == 3)
{
Console.WriteLine(“星期三”);
}
// … 依此类推直到星期日
else
{
Console.WriteLine(“无效的输入”);
}
“`

这段代码功能上没问题,但是当可能性很多时,if-else if 链会变得很长,阅读和维护都比较麻烦。

使用 switch 语句,同样的功能可以这样实现:

“`csharp
int dayOfWeek = GetUserInput(); // 假设获取到用户输入的数字

switch (dayOfWeek)
{
case 1:
Console.WriteLine(“星期一”);
break;
case 2:
Console.WriteLine(“星期二”);
break;
case 3:
Console.WriteLine(“星期三”);
break;
case 4:
Console.WriteLine(“星期四”);
break;
case 5:
Console.WriteLine(“星期五”);
break;
case 6:
Console.WriteLine(“星期六”);
break;
case 7:
Console.WriteLine(“星期日”);
break;
default:
Console.WriteLine(“无效的输入”);
break;
}
“`

是不是感觉清晰了很多?这就是 switch 语句的核心价值所在。

2. Switch 语句的基本语法

传统的 switch 语句语法结构如下:

“`csharp
switch (expression)
{
case constant-value1:
// 当 expression 的值等于 constant-value1 时执行这里的代码
code_block1;
break; // 结束当前 case 并跳出 switch 语句
case constant-value2:
// 当 expression 的值等于 constant-value2 时执行这里的代码
code_block2;
break; // 结束当前 case 并跳出 switch 语句
// … 可以有任意数量的 case
case constant-valueN:
// 当 expression 的值等于 constant-valueN 时执行这里的代码
code_blockN;
break; // 结束当前 case 并跳出 switch 语句

default:
    // 当 expression 的值不匹配任何 case 时执行这里的代码 (可选)
    default_code_block;
    break; // 结束 default 并跳出 switch 语句

}
“`

让我们分解一下这个结构:

  • switch (expression): 这是 switch 语句的起始。expression 是一个表达式,它的值将被用来与各个 case 后面的常量值进行比较。这个表达式的结果类型必须是 switch 语句支持的类型(我们稍后会详细说明)。
  • case constant-value:: 这是一个 case 标签,后面跟着一个常量值 (constant-value)。constant-value 必须是编译时可确定的常量,并且其类型必须与 expression 的类型兼容。当 expression 的值等于某个 case 后面的 constant-value 时,该 case 块下的代码就会被执行。
  • code_block;: 这是与 case 标签关联的代码块。可以包含一条或多条语句。
  • break;: 这是 switch 语句中至关重要的一部分。在传统的 C# switch 语句中,每个非空的 case 块都必须显式地结束。通常使用 break 语句来结束当前的 case 的执行,并立即跳出整个 switch 语句。如果不使用 break(或其他跳转语句如 return, throw, goto case, goto default),编译器会报错。这是 C# 与 C/C++ 的一个重要区别,C/C++ 默认会“贯穿”(fall through)到下一个 case。C# 强制要求显式结束是为了避免意外的贯穿错误。
    • 特例: 如果一个 case 块是空的(没有任何语句,包括注释),那么它后面可以紧跟着另一个 case 标签,实现多个值执行同一个代码块的效果。例如:
      csharp
      case 1:
      case 2:
      Console.WriteLine("输入了 1 或 2");
      break;

      这种空 case 的语法是允许的,并且是实现多个值共享逻辑的标准方式。
  • default:: 这是可选的 default 标签。如果 expression 的值不匹配任何 case 后面的 constant-value,那么 default 块中的代码将被执行。default 标签可以出现在 switch 块的任何位置,但通常习惯性地放在最后一个。如果 default 块存在,它也会像普通 case 一样需要显式结束(通常是 break)。

3. switch 语句支持的数据类型

在传统的 switch 语句中,expression 可以是以下类型之一:

  • 整数类型:sbyte, byte, short, ushort, int, uint, long, ulong
  • 字符类型:char
  • 布尔类型:bool (虽然可以使用,但不常见,通常 if-else 更直观)
  • 字符串类型:string (C# 2.0 及更高版本支持)
  • 枚举类型:enum
  • 可空类型:上述类型的可空形式(例如 int?, string?, MyEnum?

需要注意的是,浮点类型(float, double, decimal不能直接用作 case 标签的常量值进行精确匹配,因为浮点数的相等性比较存在精度问题。虽然 switch 表达式本身的结果类型可以是浮点数,但你在 case 后面写 case 1.0: 这样的精确匹配是不被推荐或支持的。对于浮点数的范围或近似值比较,if-else if 结构通常是更好的选择。

4. break 的重要性与替代方案

正如前面提到的,在 C# 传统 switch 中,每个非空的 case 块都必须有一个显式的跳转语句来终止。最常见的是 break

除了 break,你还可以使用:

  • return;: 如果 switch 语句在一个方法内部,return 会立即结束方法的执行,并跳出 switch
  • throw new Exception(...);: 抛出异常也会终止当前的执行流程,自然也就跳出了 switch
  • goto case constant-value;: 跳转到同一个 switch 语句中的另一个 case 标签。这通常用于处理具有共同逻辑的多个 case,但这种用法并不常见,并且可能使代码难以理解,应谨慎使用。
  • goto default;: 跳转到 default 标签。

“`csharp
int statusCode = 404;

switch (statusCode)
{
case 200:
Console.WriteLine(“成功”);
// break; // 如果这里是 return,就不需要 break 了
return; // 假设在方法内部
case 404:
Console.WriteLine(“未找到”);
break; // 必须有 break
case 500:
Console.WriteLine(“服务器错误”);
throw new InvalidOperationException(“发生服务器错误”); // 抛出异常也会退出
case 400:
case 401: // 空 case,会贯穿到 403
case 403:
Console.WriteLine(“客户端错误或权限问题”);
break; // 必须有 break
default:
Console.WriteLine(“未知状态码”);
break; // default 也需要结束
}

// 如果 switch 中使用了 return/throw,这里的代码可能不会执行
Console.WriteLine(“Switch 语句执行完毕。”); // 如果 statusCode 是 404 或 400/401/403 或 default,会执行到这里
“`

在这个例子中,如果 statusCode 是 200,方法会直接返回,Switch 语句执行完毕。 这行代码就不会打印。如果是 500,会抛出异常,也不会打印后面的行。

5. default 标签的用法与位置

default 标签是可选的。它的作用是捕获所有未被任何 case 匹配到的值。提供 default 标签是一种良好的实践,它可以提高代码的健壮性,确保在面对意外输入时程序不会悄无声息地失败或行为异常。

default 标签的位置是灵活的,可以放在 switch 块内的任何地方。然而,将其放在所有 case 标签之后是最常见的做法,因为它符合逻辑流程——先尝试所有已知情况,最后处理其他所有情况。

“`csharp
char grade = ‘B’;

switch (grade)
{
case ‘A’:
Console.WriteLine(“优秀”);
break;
default: // default 放在中间也是允许的
Console.WriteLine(“良好、及格或其他”);
break;
case ‘B’:
Console.WriteLine(“良好”);
break;
case ‘C’:
Console.WriteLine(“及格”);
break;
case ‘D’:
case ‘F’:
Console.WriteLine(“不及格”);
break;
}
// 输出: 良好
“`

即使 default 放在中间,它的逻辑行为不变:只有当没有任何 case 匹配时,default 块才会被执行。因此,为了可读性,强烈建议将 default 放在最后。

6. Switch 语句 vs. If-Else If 链

什么时候选择 switch,什么时候选择 if-else if

  • 选择 switch 的场景:

    • 你需要根据一个单个变量精确值来选择执行路径。
    • 这些值是离散的常量
    • 多个这样的离散值需要处理(通常3个或更多时,switch 的优势更明显)。
    • 当使用支持的类型(整数、字符、字符串、枚举等)时,switch 通常比等价的 if-else if 更简洁、更易读。
  • 选择 if-else if 的场景:

    • 条件涉及范围不等式(如 x > 10, y <= 5)。
    • 条件涉及多个变量(如 x > 10 && y < 20)。
    • 条件是复杂的布尔表达式
    • 只需要判断少数几个(1或2个)离散值。

在性能方面,对于处理大量离散的整数或枚举值,C# 编译器有时可以将 switch 语句优化成一个跳转表(jump table)。这种情况下,无论匹配的值是第一个还是最后一个,查找和跳转的时间复杂度接近 O(1),而 if-else if 是 O(n)(平均需要检查一半的条件)。然而,对于字符串或其他类型,或者当 case 值分布稀疏时,编译器可能不会生成跳转表,而是使用其他的比较和跳转策略,性能差异可能不那么显著。总之,在大多数应用开发场景中,选择 switch 还是 if-else if 主要取决于代码的可读性和维护性,而非过早的性能优化。

“`csharp
// if-else if 适合范围判断
int score = 85;
if (score >= 90)
{
Console.WriteLine(“优秀”);
}
else if (score >= 80)
{
Console.WriteLine(“良好”);
}
else if (score >= 60)
{
Console.WriteLine(“及格”);
}
else
{
Console.WriteLine(“不及格”);
}

// switch 适合精确值判断
string command = “start”;
switch (command)
{
case “start”:
Console.WriteLine(“开始…”);
break;
case “stop”:
Console.WriteLine(“停止…”);
break;
case “pause”:
Console.WriteLine(“暂停…”);
break;
default:
Console.WriteLine(“未知命令”);
break;
}
“`

第二部分:现代 C# 的 Switch 新特性 (C# 7.0+)

随着 C# 语言的发展,switch 语句变得越来越强大和灵活,引入了模式匹配(Pattern Matching)的概念,并在 C# 8.0 中推出了全新的 switch 表达式。这些特性极大地扩展了 switch 的适用范围,使其能够处理更复杂的条件判断。

1. 模式匹配在 Switch 语句中的应用 (C# 7.0+)

C# 7.0 引入了模式匹配,并在后续版本中不断增强。这让 switch 语句不再仅仅局限于与常量值的精确匹配,而是可以匹配表达式的类型形状属性等。

在传统的 switch 语句中,模式匹配主要体现在以下几个方面:

  • 类型模式 (is pattern): 检查表达式的类型是否与指定的类型兼容,如果匹配,可以同时将表达式转换为该类型并赋值给一个变量。

    “`csharp
    object item = “Hello, World!”; // item 可以是任何类型

    switch (item)
    {
    case int i: // 如果 item 是 int 类型,将其值赋给变量 i
    Console.WriteLine($”这是一个整数: {i}”);
    break;
    case string s: // 如果 item 是 string 类型,将其值赋给变量 s
    Console.WriteLine($”这是一个字符串: {s.Length} 个字符”);
    break;
    case bool b: // 如果 item 是 bool 类型,将其值赋给变量 b
    Console.WriteLine($”这是一个布尔值: {b}”);
    break;
    case null: // 也可以匹配 null
    Console.WriteLine(“这是一个 null 值”);
    break;
    default:
    Console.WriteLine($”未知类型: {item.GetType().Name}”);
    break;
    }
    // 输出: 这是一个字符串: 13 个字符
    ``
    这里的
    case int i:就是一个类型模式,它检查item是否是int类型,如果是,就进入该case块,并且可以在块中使用i变量,它的类型是int且值为item` 转换后的值。

  • when 子句:case 标签后面添加一个 when 子句,可以为该 case 增加一个额外的布尔条件。只有当 case 标签匹配成功 并且 when 子句的条件为 true 时,该 case 块才会被执行。

    “`csharp
    int number = 15;

    switch (number)
    {
    case int n when n > 10 && n <= 20: // 匹配大于10且小于等于20的整数
    Console.WriteLine($”数字 {n} 在 10 到 20 之间”);
    break;
    case int n when n <= 10: // 匹配小于等于10的整数
    Console.WriteLine($”数字 {n} 小于等于 10″);
    break;
    default: // 如果不是整数,或者不在上述范围内
    Console.WriteLine(“数字超出范围或类型不符”);
    break;
    }
    // 输出: 数字 15 在 10 到 20 之间
    ``when` 子句非常灵活,可以用于各种模式后面,包括常量模式、类型模式等。

通过模式匹配和 when 子句,传统的 switch 语句能够处理更丰富的条件逻辑,而不仅仅是常量相等性检查。

2. Switch 表达式 (C# 8.0+)

C# 8.0 引入了 switch 表达式,这是一种与 switch 语句功能类似但语法更简洁、用于生成一个值的新结构。它通常用于简单的映射或转换场景,可以作为 if-else if 表达式或三元运算符的更具可读性的替代。

switch 表达式的语法如下:

csharp
result = expression switch
{
pattern1 => result1,
pattern2 => result2,
// ...
patternN => resultN,
_ => defaultResult // 弃元模式 (Discard Pattern) 作为默认情况 (可选,但通常需要确保穷尽所有可能性)
};

分解一下:

  • expression switch: 这是 switch 表达式的开始。expression 是要进行匹配的表达式。
  • { ... }: 包含一系列的“arm”(臂)。
  • pattern => result: 每个 arm 包含一个模式 (pattern) 和一个 => 符号,后面跟着一个结果表达式 (result)。如果 expression 匹配 pattern,则整个 switch 表达式的值就是 result
  • pattern: 可以是前面提到的各种模式,包括常量模式、类型模式、关系模式、属性模式等。
  • result: 匹配成功时返回的值或表达式。
  • _: 这是一个弃元模式 (Discard Pattern),它匹配任何值。在 switch 表达式中,它通常用作类似传统 switch 语句中 default 的作用,用于处理所有未被其他模式匹配到的情况。如果 switch 表达式不能覆盖所有可能的输入值(即不是“穷尽的”),并且没有包含弃元模式 _,那么在运行时可能会抛出异常。因此,通常建议包含一个 _ 模式作为 fallback。

重要区别:Switch 语句 vs. Switch 表达式

特性 Switch 语句 (Statement) Switch 表达式 (Expression)
用途 执行不同的代码块 (副作用) 根据输入返回一个值
语法 switch (...) { case ...: ... break; ... } ... switch { ... => ..., ... }
结束方式 break, return, throw, goto case/default => 后面的表达式求值完毕即返回该值,无需 break
返回值 没有直接返回值 必须返回一个值
Default 使用 default: 标签 使用弃元模式 _
穷尽性 不需要强制穷尽所有可能性 (default 可选) 通常需要穷尽所有可能性 (否则可能运行时错误),常使用 _

Switch 表达式示例:

将数字映射到星期几的字符串:

“`csharp
int day = 3;

string dayName = day switch
{
1 => “星期一”,
2 => “星期二”,
3 => “星期三”,
4 => “星期四”,
5 => “星期五”,
6 => “星期六”,
7 => “星期日”,
_ => “无效的日期” // 弃元模式处理其他所有情况
};

Console.WriteLine(dayName); // 输出: 星期三
“`

这个例子比传统的 switch 语句写起来更紧凑,并且直接将结果赋值给 dayName 变量。

Switch 表达式也可以结合模式匹配和 when 子句:

“`csharp
object data = “hello”;

string dataTypeInfo = data switch
{
int i when i > 100 => $”大整数: {i}”, // 类型模式 + when
int i => $”小整数: {i}”, // 类型模式 (注意顺序,会先匹配上面的条件)
string s when s.Length > 5 => $”长字符串: {s}”, // 类型模式 + when
string s => $”短字符串: {s}”, // 类型模式
null => “空值”, // 常量模式
_ => $”未知类型: {data.GetType().Name}” // 弃元模式
};

Console.WriteLine(dataTypeInfo); // 输出: 短字符串: hello
``
注意,在
switch` 表达式中,模式的顺序很重要。它们会按顺序进行评估,第一个匹配的模式对应的结果将被返回。因此,更具体的模式通常应该放在更通用的模式之前。

3. 更高级的模式匹配 (C# 9.0+)

C# 9.0 及更高版本进一步增强了模式匹配的能力,使得 switch 表达式和 switch 语句(虽然 switch 表达式是模式匹配更常见的应用场景)能够处理更复杂的条件。

  • 关系模式 (Relational Patterns): 允许使用关系运算符 (<, >, <=, >=) 直接在 case 或模式中比较表达式的值。

    “`csharp
    int temperature = 25;

    string feeling = temperature switch
    {
    < 0 => “极寒”,
    < 10 => “很冷”,
    < 20 => “凉爽”,
    < 30 => “温暖”,
    < 40 => “炎热”,
    _ => “极热或未知”
    };
    // 注意:关系模式也是按顺序评估的。比如 < 20 会在 < 10 之后评估,所以它只匹配 10-19 的范围。
    // 这使得表达范围判断变得非常直观。

    Console.WriteLine(feeling); // 输出: 温暖
    “`

    关系模式也可以与 when 子句结合使用,尽管通常关系模式本身已经足够表达范围。

  • 逻辑模式 (Logical Patterns): 允许使用逻辑运算符 and, or, not (或 !) 组合其他模式。

    “`csharp
    int value = 5;

    string description = value switch
    {
    > 0 and < 10 => “正数且小于10”, // 组合关系模式
    < 0 or > 100 => “负数或大于100”, // 组合关系模式
    not 0 => “非零”, // 否定模式 (匹配所有非0的值)
    _ => “零”
    };

    Console.WriteLine(description); // 输出: 正数且小于10
    “`
    逻辑模式让你可以构建更精细的匹配条件。

  • 属性模式 (Property Patterns): 允许匹配对象的特定属性的值。

    假设有一个 Order 类:

    “`csharp
    public class Order
    {
    public int OrderId { get; set; }
    public decimal Total { get; set; }
    public string Status { get; set; } // 例如: “Pending”, “Shipped”, “Delivered”
    public Customer Customer { get; set; } // 假设 Customer 类有 Name 属性
    }

    public class Customer
    {
    public string Name { get; set; }
    // … 其他属性
    }
    “`

    使用属性模式进行匹配:

    “`csharp
    Order order = new Order { OrderId = 101, Total = 150.75m, Status = “Shipped”, Customer = new Customer { Name = “Alice” } };

    string orderStatus = order switch
    {
    { Status: “Pending” } => “订单待处理”, // 匹配 Status 属性是 “Pending” 的 Order 对象
    { Status: “Shipped”, Total: > 100 } => “大额订单已发货”, // 组合属性模式和关系模式
    { Status: “Shipped” } => “订单已发货 (非大额)”,
    { Status: “Delivered”, Customer.Name: “Bob” } => “Bob 的订单已送达”, // 嵌套属性模式
    { Status: “Delivered” } => “订单已送达”,
    null => “订单对象为空”, // 匹配 null
    _ => “未知订单状态”
    };

    Console.WriteLine(orderStatus); // 输出: 大额订单已发货
    ``
    属性模式非常强大,它允许你根据对象的内部状态进行复杂的条件判断,而无需写一长串的
    if (order != null && order.Status == “Shipped” && order.Total > 100)`。

这些现代模式匹配特性使得 switch 语句和 switch 表达式成为处理复杂分发逻辑的有力工具,提高了代码的表现力和可读性。

第三部分:实用建议与常见陷阱

1. 使用枚举 (Enum) 让 Switch 更安全、更清晰

switch 语句中使用枚举类型是一种非常推荐的做法。枚举提供了命名常量,提高了代码的可读性和可维护性。更重要的是,使用枚举可以减少因拼写错误等引起的潜在 bug,并且在面对新的枚举成员时,编译器或 IDE 可以提供警告(例如,如果 switch 语句没有覆盖枚举的所有成员)。

“`csharp
public enum TrafficLight
{
Red,
Yellow,
Green
}

TrafficLight currentLight = TrafficLight.Green;

switch (currentLight)
{
case TrafficLight.Red:
Console.WriteLine(“停车”);
break;
case TrafficLight.Yellow:
Console.WriteLine(“减速/等待”);
break;
case TrafficLight.Green:
Console.WriteLine(“通行”);
break;
// 通常建议包含 default 处理非预期的枚举值(虽然很少发生,除非外部数据源传入非法值)
default:
Console.WriteLine(“未知信号灯状态”);
break;
}
“`

2. 确保 Switch 表达式的穷尽性

使用 switch 表达式时,如果输入类型不是可空的引用类型或可空值类型,并且你没有包含一个匹配所有剩余可能值的模式(通常是弃元模式 _),编译器可能会发出警告或错误,提示 switch 表达式不是穷尽的(non-exhaustive)。这意味着存在某些可能的输入值不会匹配任何模式。在运行时,如果遇到这样的值,switch 表达式将抛出 System.Runtime.CompilerServices.SwitchExpressionException

为了避免这种情况,请始终确保你的 switch 表达式能够处理所有可能的输入值。最简单的方法是包含一个 _ 弃元模式作为最后一个 arm:

“`csharp
// 假设 StatusCode 是一个 int
int statusCode = 999;

string statusDescription = statusCode switch
{
200 => “OK”,
404 => “Not Found”,
500 => “Internal Server Error”,
// … 其他已知的状态码
_ => “未知状态码” // 确保所有其他 int 值都被处理
};
“`

如果输入类型是可空的(例如 int?, string?, MyEnum?),你需要显式处理 null 情况,除非弃元模式 _ 包含了对 null 的处理:

“`csharp
int? maybeNumber = null;

string result = maybeNumber switch
{
1 => “数字是 1”,
> 10 => “数字大于 10”,
null => “值是 null”, // 显式处理 null
_ => “其他数字” // 处理非 null 且不匹配前面模式的情况
};

Console.WriteLine(result); // 输出: 值是 null
``
这里的
_模式会匹配所有非 null 且不等于 1 且不大于 10 的int` 值。

3. 避免在 Case 块中编写过于复杂的逻辑

虽然你可以在 casedefault 块中编写任意复杂的代码,但如果代码块变得很长或包含嵌套结构,这会降低 switch 语句的可读性。良好的实践是将复杂的逻辑提取到单独的方法中,然后在 case 块中调用这些方法。

“`csharp
// 不推荐: case 块中逻辑复杂
switch (command)
{
case “process”:
// 大量处理逻辑,循环,条件判断等…
Console.WriteLine(“开始处理…”);
// … 很多行代码
break;
// …
}

// 推荐: 将逻辑提取到方法中
switch (command)
{
case “process”:
ProcessData(); // 调用单独的方法
break;
// …
}

void ProcessData()
{
// 大量处理逻辑…
Console.WriteLine(“正在处理数据…”);
// …
}
“`

4. 理解模式匹配的顺序

switch 表达式和带有模式匹配的 switch 语句中,模式是按顺序进行评估的。一旦找到第一个匹配的模式,对应的代码块或结果就会被执行/返回,然后退出 switch。这意味着你应该将更具体或更窄的模式放在更通用或更宽泛的模式之前。

“`csharp
// 错误的顺序示例 (在 switch 表达式或语句中)
int x = 5;
string range = x switch
{
> 0 => “正数”, // 这个模式会匹配所有正数,包括大于100的
> 100 => “大于100的正数”, // 这一行永远不会被匹配到,因为所有大于100的数已经被上面的模式捕获了
_ => “非正数”
};
Console.WriteLine(range); // 输出: 正数 (即使 x = 150 也是输出 正数)

// 正确的顺序示例
int y = 150;
string correctRange = y switch
{
> 100 => “大于100的正数”, // 先检查最具体的范围
> 0 => “正数”, // 再检查更宽泛的范围
_ => “非正数”
};
Console.WriteLine(correctRange); // 输出: 大于100的正数
“`
理解这个顺序对于正确使用模式匹配至关重要。

5. 传统 Switch 语句中的贯穿 (Fall-through)

再次强调,C# 传统 switch 语句不允许非空的 case 块自动贯穿到下一个 case。如果你需要让多个 case 执行相同的代码,有两种方法:

  • 使用空的 case 标签:
    csharp
    case 1:
    case 2:
    Console.WriteLine("值为 1 或 2");
    break;
  • 使用 goto casegoto default (不推荐用于初学者,可能导致代码难以理解):
    csharp
    int num = 5;
    switch (num)
    {
    case 5:
    Console.WriteLine("处理 5 的特有逻辑");
    goto case 10; // 跳转到 case 10
    case 10:
    Console.WriteLine("处理 5 和 10 的共享逻辑");
    break;
    default:
    Console.WriteLine("其他");
    break;
    }
    // 输出:
    // 处理 5 的特有逻辑
    // 处理 5 和 10 的共享逻辑

除非必要且非常清晰,否则优先使用空的 case 标签来实现多个值共享逻辑。

结论

C# 的 switch 语句是一个强大而灵活的控制流结构,尤其适用于基于单个表达式离散值的选择场景。从传统的基于常量值的匹配,到现代 C# 通过模式匹配和 switch 表达式带来的类型检查、属性检查、范围判断和逻辑组合能力,switch 的功能得到了极大的扩展。

掌握 switch 语句及其现代特性,能够帮助你编写出更清晰、更简洁、更富有表现力的 C# 代码。在处理多分支逻辑时,请考虑 switch 是否是比 if-else if 更合适的工具。熟练运用 switch 表达式和各种模式,将是你在现代 C# 开发中迈出的重要一步。

实践是学习的最佳途径。尝试在你自己的代码中使用 switch 语句和 switch 表达式,特别是结合模式匹配,去解决实际问题,你将更快地掌握这些强大的工具。

希望这篇详细的指南对你理解和使用 C# switch 语句有所帮助!祝你编程愉快!


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部