C# switch 语句:从传统分支到模式匹配的艺术
引言:代码世界的「分类器」
想象你走进一家奶茶店,店员问:「需要什么口味?」你回答「原味」「抹茶」或「巧克力」——店员根据这个精确值,直接执行对应的制作流程。这就是 switch 语句的原型:不是「大于 18 岁」这样的范围判断,而是「周一」「周二」「周三」这样的离散值匹配。
switch 语句是 C# 中处理多路分支的核心结构。与 if-else 的「条件判断」不同,switch 擅长「值匹配」——把一个变量的值与多个候选值逐一比对,命中后执行对应分支。随着 C# 版本的演进,switch 从简单的数值匹配,进化为支持模式匹配的强大工具,甚至成为函数式编程风格的重要载体。
一、基础定义与核心作用
1.1 什么是 switch 语句
switch 语句是一种选择结构,根据表达式的值,从多个候选分支中选择其一执行。它解决的核心问题是:当同一个变量需要与多个离散值比较时,避免冗长的 if-else-if 链。
// if-else 链:冗长且重复
int day = 3;
if (day == 1) Console.WriteLine("周一");
else if (day == 2) Console.WriteLine("周二");
else if (day == 3) Console.WriteLine("周三");
else if (day == 4) Console.WriteLine("周四");
else Console.WriteLine("其他");
// switch 语句:简洁清晰
switch (day)
{
case 1: Console.WriteLine("周一"); break;
case 2: Console.WriteLine("周二"); break;
case 3: Console.WriteLine("周三"); break;
case 4: Console.WriteLine("周四"); break;
default: Console.WriteLine("其他"); break;
}1.2 核心作用
- 消除重复:避免反复书写
else if (x == ...) - 提升可读性:分支结构一目了然,意图明确
- 编译器优化:某些场景下编译器可生成跳转表,性能优于链式判断
- 模式匹配:C# 7.0+ 后,switch 成为模式匹配的主战场
二、基础语法格式详解
2.1 传统 switch 语句的完整结构
switch (表达式) // switch 表达式:要匹配的值
{
case 常量1: // case 标签:候选匹配值
语句块1; // 命中后执行的代码
break; // 终止当前分支(C# 中必须)
case 常量2:
语句块2;
break;
case 常量3: // 多个 case 共享同一代码块(fall-through)
case 常量4:
语句块3;
break;
default: // 默认分支:所有 case 都不命中时执行
默认语句块;
break;
}语法要点:
| 要素 | 说明 |
|---|---|
switch 表达式 | 支持 int、char、string、enum、bool 及可空类型 |
case 标签 | 必须是编译时常量(字面量、const 变量、枚举成员) |
break | C# 强制要求每个分支以 break、return、throw 或 goto 结束 |
default | 可选,通常放最后;不命中任何 case 时执行 |
fall-through | C# 禁止隐式贯穿,但允许多个 case 标签共享同一代码块 |
2.2 完整的可运行示例
// 场景:根据星期几输出课程安排
int dayOfWeek = 3;
switch (dayOfWeek)
{
case 1: // 周一
Console.WriteLine("周一:数学 + 英语");
break;
case 2: // 周二
Console.WriteLine("周二:物理 + 化学");
break;
case 3: // 周三
case 4: // 周四(与周三课程相同)
Console.WriteLine("周三/四:体育课 + 自习");
break;
case 5: // 周五
Console.WriteLine("周五:班会 + 大扫除");
break;
case 6: // 周六
case 7: // 周日
Console.WriteLine("周末:休息");
break;
default: // 非法输入
Console.WriteLine("无效星期值");
break;
}
// 输出:周三/四:体育课 + 自习2.3 枚举类型:switch 的最佳搭档
enum Color { Red, Green, Blue }
Color favorite = Color.Green;
switch (favorite)
{
case Color.Red:
Console.WriteLine("红色:热情");
break;
case Color.Green:
Console.WriteLine("绿色:自然");
break;
case Color.Blue:
Console.WriteLine("蓝色:冷静");
break;
// 枚举的 default 是可选的,因为编译器会检查穷尽性
}
// 输出:绿色:自然2.4 字符串匹配:区分大小写的细节
string command = "start";
switch (command.ToLower()) // 统一转为小写,避免大小写问题
{
case "start":
Console.WriteLine("启动服务");
break;
case "stop":
Console.WriteLine("停止服务");
break;
case "restart":
Console.WriteLine("重启服务");
break;
default:
Console.WriteLine("未知命令");
break;
}三、版本演进:从传统到现代
3.1 C# 7.0:模式匹配的萌芽
C# 7.0 在 switch 中引入了类型模式和 when 守卫,打破了「只能匹配常量」的限制。
object obj = "Hello";
switch (obj)
{
case int i: // 类型模式:匹配 int 类型
Console.WriteLine($"整数:{i}");
break;
case string s when s.Length > 5: // when 守卫:附加条件
Console.WriteLine($"长字符串:{s}");
break;
case string s: // 无守卫的类型模式
Console.WriteLine($"短字符串:{s}");
break;
case null: // null 模式
Console.WriteLine("空引用");
break;
default:
Console.WriteLine("其他类型");
break;
}
// 输出:短字符串:Hello3.2 C# 8.0:switch 表达式(Switch Expression)
革命性变化:switch 从「语句」进化为「表达式」,有返回值,语法更简洁。
// 传统 switch 语句:需要 break,无返回值
string GetGrade(int score)
{
string grade;
switch (score / 10)
{
case 10:
case 9:
grade = "A";
break;
case 8:
grade = "B";
break;
case 7:
grade = "C";
break;
default:
grade = "D";
break;
}
return grade;
}
// C# 8.0 switch 表达式:有返回值,箭头语法
string GetGradeModern(int score) => (score / 10) switch
{
10 => "A", // 模式 => 表达式,无需 break
9 => "A",
8 => "B",
7 => "C",
_ => "D" // _ 表示默认(弃元模式)
};
// 更简洁:直接在赋值中使用
int score = 85;
string grade = (score / 10) switch
{
10 or 9 => "优秀", // C# 9.0 的 or 模式
8 => "良好",
7 => "及格",
_ => "不及格"
};switch 表达式语法要点:
- 使用
=>箭头替代case:和break - 每个分支是「模式 => 结果表达式」
_是弃元模式,表示「匹配任何值」,相当于 default- 编译器强制要求穷尽匹配(exhaustiveness),否则编译警告
3.3 C# 9.0:模式匹配增强
C# 9.0 引入了关系模式、逻辑模式、类型模式简化等。
int age = 25;
string category = age switch
{
< 0 => "非法年龄", // 关系模式:小于
>= 0 and < 18 => "未成年", // 逻辑模式:and 组合
>= 18 and < 60 => "成年人",
>= 60 => "老年人"
};
// 逻辑模式:or、and、not
bool IsWorkingAge(int a) => a is >= 18 and <= 65;
// 类型模式简化:省略变量声明(当不需要使用变量时)
object obj = 42;
string desc = obj switch
{
int => "是整数", // 无需 case int i
string => "是字符串",
_ => "其他类型"
};3.4 C# 10.0+:后续优化
- C# 10:扩展了
or模式的组合能力,支持更复杂的嵌套模式 - C# 11:
list模式(列表模式),支持数组/集合的匹配 - C# 12:主构造函数中更灵活的 switch 使用
// C# 11 列表模式(预览)
int[] numbers = { 1, 2, 3 };
string result = numbers switch
{
[] => "空数组",
[1] => "只有 1",
[1, 2] => "1 和 2",
[1, ..] => "以 1 开头", // .. 表示剩余元素
[.., 3] => "以 3 结尾",
_ => "其他"
};四、模式匹配详解
4.1 常量模式(Constant Pattern)
最基础的匹配:与常量值比较。
object obj = 42;
string result = obj switch
{
0 => "零",
42 => "答案",
-1 => "负数",
_ => "其他"
};
// 输出:答案支持的常量类型:int、long、char、string、bool、枚举、decimal、double、float(注意浮点精度问题)。
4.2 类型模式(Type Pattern)
匹配类型:判断对象是否属于某个类型。
object[] items = { 1, "hello", 3.14, true, null };
foreach (var item in items)
{
string desc = item switch
{
int i => $"整数:{i}(平方={i * i})",
string s => $"字符串:{s}(长度={s.Length})",
double d => $"浮点数:{d:F2}",
bool b => $"布尔:{b}",
null => "空引用",
_ => "未知类型"
};
Console.WriteLine(desc);
}
// 输出:
// 整数:1(平方=1)
// 字符串:hello(长度=5)
// 浮点数:3.14
// 布尔:True
// 空引用4.3 关系模式(Relational Pattern)— C# 9.0+
比较匹配:>, <, >=, <=。
double temperature = 22.5;
string weather = temperature switch
{
< -10 => "严寒",
>= -10 and < 0 => "寒冷",
>= 0 and < 15 => "凉爽",
>= 15 and < 25 => "温暖",
>= 25 and < 35 => "炎热",
>= 35 => "酷暑"
};
// 输出:温暖4.4 逻辑模式(Logical Pattern)— C# 9.0+
组合匹配:and(且)、or(或)、not(非)。
int month = 7;
string season = month switch
{
>= 3 and <= 5 => "春季",
>= 6 and <= 8 => "夏季",
>= 9 and <= 11 => "秋季",
12 or 1 or 2 => "冬季",
_ => "非法月份"
};
// not 模式:排除特定情况
bool IsNotWeekend(DayOfWeek day) => day is not (DayOfWeek.Saturday or DayOfWeek.Sunday);
// 输出:夏季4.5 属性模式(Property Pattern)
匹配对象的属性值:无需先类型转换再判断属性。
record Person(string Name, int Age, bool IsVip);
Person[] people =
{
new("张三", 25, true),
new("李四", 17, false),
new("王五", 30, true),
new("赵六", 65, false)
};
foreach (var p in people)
{
string level = p switch
{
// 属性模式:匹配 Age >= 60 且 IsVip 为 true
{ Age: >= 60, IsVip: true } => "尊贵长者",
{ Age: >= 60 } => "普通长者",
{ IsVip: true } => "VIP 客户",
{ Age: < 18 } => "未成年",
_ => "普通客户"
};
Console.WriteLine($"{p.Name}:{level}");
}
// 输出:
// 张三:VIP 客户
// 李四:未成年
// 王五:VIP 客户
// 赵六:普通长者嵌套属性模式:
record Address(string City, string ZipCode);
record User(string Name, Address Addr);
User user = new("小明", new Address("北京", "100000"));
string region = user switch
{
{ Addr: { City: "北京" or "上海" } } => "一线城市",
{ Addr: { City: "广州" } } => "一线城市",
_ => "其他城市"
};4.6 位置模式(Positional Pattern)
基于解构的匹配:适用于 record 或支持 Deconstruct 的类型。
record Point(int X, int Y);
Point[] points = { new(0, 0), new(1, 0), new(0, 1), new(1, 1), new(5, 5) };
foreach (var p in points)
{
string location = p switch
{
(0, 0) => "原点", // 位置模式:匹配 X=0, Y=0
(0, _) => "Y 轴上", // _ 表示任意 Y
(_, 0) => "X 轴上", // _ 表示任意 X
(var x, var y) when x == y => "对角线", // 带 when 的位置模式
_ => "普通位置"
};
Console.WriteLine($"({p.X}, {p.Y}):{location}");
}
// 输出:
// (0, 0):原点
// (1, 0):X 轴上
// (0, 1):Y 轴上
// (1, 1):对角线
// (5, 5):对角线4.7 组合示例:复杂业务规则
record Order(int Id, string Status, decimal Amount, bool IsPaid, DateTime CreateTime);
string GetOrderAction(Order order) => order switch
{
// 未支付且金额大于 1000 的待处理订单
{ Status: "Pending", IsPaid: false, Amount: > 1000 } => "需要人工审核",
// 已支付但超过 7 天未发货
{ IsPaid: true, CreateTime: var t } when (DateTime.Now - t).Days > 7 => "催发货",
// 已取消的订单
{ Status: "Cancelled" } => "已关闭",
// 小额待支付订单(位置模式 + 属性模式)
{ Status: "Pending", IsPaid: false, Amount: <= 1000 } => "自动提醒",
_ => "正常处理"
};五、实战注意事项
5.1 覆盖性检查与穷尽匹配
传统 switch 语句:编译器不强制穷尽匹配,default 是可选的。
enum Color { Red, Green, Blue }
Color c = Color.Red;
// 传统 switch:不写 default 也能编译,但运行时不匹配就跳过
switch (c)
{
case Color.Red:
Console.WriteLine("红");
break;
// 没有处理 Green 和 Blue,编译通过但可能漏处理
}switch 表达式:编译器强制要求穷尽匹配,否则会警告。
// ❌ 编译警告:CS8509:switch 表达式未处理所有可能值
string name = c switch
{
Color.Red => "红色"
// 缺少 Green、Blue 和 default(_)
};
// ✅ 正确:添加弃元模式处理所有剩余情况
string name2 = c switch
{
Color.Red => "红色",
Color.Green => "绿色",
Color.Blue => "蓝色",
_ => "未知" // 必须处理所有情况
};5.2 Fall-through 规则的历史变化
| 版本 | 规则 |
|---|---|
| C/C++ | 允许隐式贯穿(fall-through),不加 break 会继续执行下一个 case |
| C# 1.0-6.0 | 禁止隐式贯穿,但允许多个 case 标签共享同一代码块 |
| C# 7.0+ | 引入 when 守卫,守卫失败时不会贯穿到下一个 case |
| C# 8.0+ | switch 表达式彻底消除贯穿概念,每个分支独立 |
// C/C++ 风格(C# 不支持!)
// case 1:
// Console.WriteLine("一");
// // 没有 break,会贯穿到 case 2
// case 2:
// Console.WriteLine("二");
// break;
// C# 的正确共享方式:多个 case 标签连续排列
int value = 1;
switch (value)
{
case 1:
case 2:
case 3:
Console.WriteLine("一、二或三"); // 1、2、3 都会执行这里
break;
default:
Console.WriteLine("其他");
break;
}5.3 性能对比
| 场景 | 性能特点 |
|---|---|
| 少量分支(<5) | if-else 与 switch 性能相当 |
| 大量分支(>10) | switch 可能生成跳转表,性能更优 |
| 字符串匹配 | switch 使用哈希或字典查找,优于链式 if-else |
| 模式匹配 | 略低于常量匹配,但代码可读性收益远大于性能损失 |
实测建议:除非在极端性能敏感场景(如每秒百万次调用),否则优先选择可读性更好的方案。
5.4 switch vs if-else 选型判断
// 场景1:精确值匹配(枚举、常量)→ 优先 switch
enum Status { Active, Inactive, Pending }
string GetMessage(Status s) => s switch // ✅ 推荐
{
Status.Active => "活跃",
Status.Inactive => "停用",
Status.Pending => "待审核",
_ => "未知"
};
// 场景2:范围判断 → 必须 if-else(或 switch 表达式的关系模式)
int score = 85;
// if-else:自然直观
if (score >= 90) Console.WriteLine("A");
else if (score >= 80) Console.WriteLine("B");
// switch 表达式:同样可行,但关系模式略繁琐
string grade = score switch
{
>= 90 => "A",
>= 80 => "B",
>= 60 => "C",
_ => "D"
};
// 场景3:复杂对象判断 → switch 表达式 + 属性模式(更优雅)
// 场景4:简单布尔判断 → if 语句(无需 switch)5.5 常见坑点与规避
坑点1:浮点数匹配的精度问题
double x = 0.1 + 0.2;
// ❌ 危险:浮点数不能精确匹配
string result = x switch
{
0.3 => "等于 0.3",
_ => "不等于 0.3"
};
// 实际输出:不等于 0.3(因为 0.1+0.2 = 0.30000000000000004)
// ✅ 规避:使用范围或阈值
string safe = x switch
{
>= 0.299 and <= 0.301 => "约等于 0.3",
_ => "其他"
};坑点2:字符串匹配的 null 值
string input = null;
// ❌ 传统 switch:null 会进入 default(如果无 default 则跳过)
switch (input)
{
case "a": Console.WriteLine("A"); break;
default: Console.WriteLine("默认或 null"); break;
}
// ❌ switch 表达式:null 会匹配 _,但可能不是预期
string r = input switch
{
"a" => "A",
_ => "默认" // null 也走这里
};
// ✅ 明确处理 null
string safe = input switch
{
null => "空引用",
"a" => "A",
_ => "默认"
};坑点3:when 守卫中的副作用
int counter = 0;
// ❌ 危险:when 中修改状态,导致逻辑混乱
string Check(int x) => x switch
{
> 0 when counter++ > 0 => "正数", // 副作用!每次调用 counter 都变
_ => "其他"
};
// ✅ 规避:when 中只做纯判断,不修改状态
bool IsPositive(int x) => x > 0;
string SafeCheck(int x) => x switch
{
_ when IsPositive(x) => "正数",
_ => "其他"
};六、综合实战案例:订单状态处理系统
业务场景
电商系统需要根据订单状态执行不同操作:
- 待支付:超时自动取消,支持手动支付
- 已支付:安排发货,超时提醒
- 已发货:物流跟踪,确认收货
- 已完成:评价邀请,售后申请
- 已取消:退款处理,库存回补
完整实现
using System;
// 订单状态枚举
public enum OrderStatus
{
Pending, // 待支付
Paid, // 已支付
Shipped, // 已发货
Completed, // 已完成
Cancelled // 已取消
}
// 订单记录(C# 9.0 record)
public record Order(
int Id,
OrderStatus Status,
decimal Amount,
DateTime CreateTime,
DateTime? PayTime,
bool IsVipCustomer
);
// 处理结果
public record ProcessResult(string Action, string Message, bool NeedNotify);
public class OrderProcessor
{
// 核心方法:使用 switch 表达式处理订单
public ProcessResult ProcessOrder(Order order) => order switch
{
// ========== 待支付订单 ==========
// 属性模式 + 关系模式 + 逻辑模式
{ Status: OrderStatus.Pending, Amount: > 10000 } =>
new("审核", $"订单 {order.Id} 金额过大({order.Amount:C}),需人工审核", true),
{ Status: OrderStatus.Pending, IsVipCustomer: true } =>
new("提醒", $"VIP 订单 {order.Id} 待支付,发送专属提醒", true),
{ Status: OrderStatus.Pending, CreateTime: var t } when IsExpired(t) =>
new("取消", $"订单 {order.Id} 已超时(创建时间:{t:MM-dd HH:mm}),自动取消", false),
{ Status: OrderStatus.Pending } =>
new("等待", $"订单 {order.Id} 待支付,等待用户操作", false),
// ========== 已支付订单 ==========
// 位置模式:解构 PayTime 判断发货时效
{ Status: OrderStatus.Paid, PayTime: var pt } when IsShippingOverdue(pt) =>
new("催发货", $"订单 {order.Id} 支付后超 48 小时未发货", true),
{ Status: OrderStatus.Paid, Amount: > 5000 } =>
new("优先发货", $"大额订单 {order.Id},安排优先发货", true),
{ Status: OrderStatus.Paid } =>
new("发货", $"订单 {order.Id} 正常发货流程", false),
// ========== 已发货订单 ==========
{ Status: OrderStatus.Shipped, CreateTime: var t } when (DateTime.Now - t).Days > 30 =>
new("自动确认", $"订单 {order.Id} 发货超 30 天,自动确认收货", false),
{ Status: OrderStatus.Shipped } =>
new("跟踪", $"订单 {order.Id} 物流跟踪中", false),
// ========== 已完成订单 ==========
{ Status: OrderStatus.Completed, IsVipCustomer: true } =>
new("回访", $"VIP 订单 {order.Id} 已完成,安排满意度回访", true),
{ Status: OrderStatus.Completed } =>
new("评价", $"订单 {order.Id} 邀请用户评价", false),
// ========== 已取消订单 ==========
{ Status: OrderStatus.Cancelled, PayTime: not null } =>
new("退款", $"订单 {order.Id} 已取消,启动退款流程", true),
{ Status: OrderStatus.Cancelled } =>
new("关闭", $"订单 {order.Id} 已取消,释放库存", false),
// ========== 兜底 ==========
_ => new("未知", $"订单 {order.Id} 状态异常,需人工排查", true)
};
// 辅助方法:纯函数,无副作用
private static bool IsExpired(DateTime createTime) =>
(DateTime.Now - createTime).Hours > 24;
private static bool IsShippingOverdue(DateTime? payTime) =>
payTime.HasValue && (DateTime.Now - payTime.Value).Hours > 48;
}
// 测试程序
class Program
{
static void Main()
{
var processor = new OrderProcessor();
// 构造测试订单
var orders = new[]
{
new Order(1, OrderStatus.Pending, 15000m, DateTime.Now.AddHours(-1), null, false),
new Order(2, OrderStatus.Pending, 500m, DateTime.Now.AddHours(-25), null, false),
new Order(3, OrderStatus.Pending, 200m, DateTime.Now.AddHours(-2), null, true),
new Order(4, OrderStatus.Paid, 8000m, DateTime.Now.AddDays(-3), DateTime.Now.AddDays(-2), false),
new Order(5, OrderStatus.Paid, 300m, DateTime.Now.AddDays(-1), DateTime.Now.AddDays(-1), false),
new Order(6, OrderStatus.Shipped, 600m, DateTime.Now.AddDays(-35), DateTime.Now.AddDays(-33), false),
new Order(7, OrderStatus.Completed, 1200m, DateTime.Now.AddDays(-10), DateTime.Now.AddDays(-11), true),
new Order(8, OrderStatus.Cancelled, 900m, DateTime.Now.AddDays(-5), DateTime.Now.AddDays(-4), false),
new Order(9, OrderStatus.Cancelled, 100m, DateTime.Now.AddDays(-1), null, false)
};
Console.WriteLine("========== 订单处理结果 ==========\n");
foreach (var order in orders)
{
var result = processor.ProcessOrder(order);
Console.WriteLine($"订单 {order.Id,2} | 状态:{order.Status,-10} | 金额:{order.Amount,8:C} | VIP:{order.IsVipCustomer,-5}");
Console.WriteLine($" | 动作:{result.Action,-8} | 通知:{result.NeedNotify,-5} | {result.Message}");
Console.WriteLine();
}
}
}输出示例
========== 订单处理结果 ==========
订单 1 | 状态:Pending | 金额:¥15,000.00 | VIP:False
| 动作:审核 | 通知:True | 订单 1 金额过大(¥15,000.00),需人工审核
订单 2 | 状态:Pending | 金额: ¥500.00 | VIP:False
| 动作:取消 | 通知:False | 订单 2 已超时(创建时间:10-06 07:00),自动取消
订单 3 | 状态:Pending | 金额: ¥200.00 | VIP:True
| 动作:提醒 | 通知:True | VIP 订单 3 待支付,发送专属提醒
订单 4 | 状态:Paid | 金额: ¥8,000.00 | VIP:False
| 动作:优先发货 | 通知:True | 大额订单 4,安排优先发货
订单 5 | 状态:Paid | 金额: ¥300.00 | VIP:False
| 动作:发货 | 通知:False | 订单 5 正常发货流程
订单 6 | 状态:Shipped | 金额: ¥600.00 | VIP:False
| 动作:自动确认 | 通知:False | 订单 6 发货超 30 天,自动确认收货
订单 7 | 状态:Completed | 金额: ¥1,200.00 | VIP:True
| 动作:回访 | 通知:True | VIP 订单 7 已完成,安排满意度回访
订单 8 | 状态:Cancelled | 金额: ¥900.00 | VIP:False
| 动作:退款 | 通知:True | 订单 8 已取消,启动退款流程
订单 9 | 状态:Cancelled | 金额: ¥100.00 | VIP:False
| 动作:关闭 | 通知:False | 订单 9 已取消,释放库存七、核心知识点总结
7.1 版本演进速查表
| 版本 | 特性 | 示例 |
|---|---|---|
| C# 1.0 | 传统 switch 语句 | switch(x) { case 1: ... break; } |
| C# 7.0 | 类型模式 + when 守卫 | case int i when i > 0: |
| C# 8.0 | switch 表达式 | x switch { 1 => "一", _ => "其他" } |
| C# 9.0 | 关系/逻辑/属性/位置模式 | { Age: >= 18 }, (0, 0) |
| C# 10.0 | 扩展 or 模式组合 | 更复杂的嵌套 or |
| C# 11.0 | 列表模式 | [1, ..], [.., 3] |
7.2 模式匹配速查表
| 模式类型 | 语法示例 | 说明 |
|---|---|---|
| 常量模式 | 42, "hello", Color.Red | 匹配具体值 |
| 类型模式 | int i, string s | 匹配类型并捕获变量 |
| 关系模式 | > 0, < 100, >= 18 | 范围比较 |
| 逻辑模式 | and, or, not | 组合多个模式 |
| 属性模式 | { Age: >= 18 } | 匹配对象属性 |
| 位置模式 | (0, 0), (var x, var y) | 解构匹配 |
| 弃元模式 | _ | 匹配任意值(兜底) |
| var 模式 | var x | 匹配任意值并捕获 |
7.3 最佳实践指南
- 优先使用 switch 表达式:代码更简洁,编译器强制穷尽匹配
- 枚举是 switch 的最佳搭档:类型安全 + 智能提示 + 重构支持
- 用
_兜底所有未预见情况:避免漏处理新增枚举值 - when 守卫保持纯判断:不修改状态,不产生副作用
- 复杂业务用属性模式:比多层 if-else 嵌套更易读
- 字符串匹配注意 null 和大小写:显式处理 null,统一 ToLower/ToUpper
- 浮点数避免精确匹配:用范围或阈值替代
- 性能敏感场景实测:不要凭直觉,用 BenchmarkDotNet 验证
7.4 传统 vs 现代:何时用哪个
| 场景 | 推荐方案 |
|---|---|
| 需要返回值的简单映射 | switch 表达式 |
| 分支内需要多行复杂逻辑 | 传统 switch 语句 |
| 需要 fall-through 共享代码 | 传统 switch(多个 case 标签) |
| 模式匹配 + 穷尽检查 | switch 表达式 |
| 兼容旧版 C#(< 8.0) | 传统 switch 语句 |
结语
switch 语句的演进史,就是 C# 语言「让代码更表达意图」的缩影。从最初简单的数值跳转,到如今支持模式匹配的函数式风格,switch 已经从一个「控制流工具」进化为「数据解构与业务规则表达」的核心武器。
掌握 switch 的关键心法:
- 语法上:表达式优于语句,模式优于常量
- 设计上:穷尽匹配是底线,
_兜底是保险 - 实战上:属性模式处理复杂对象,位置模式处理解构,when 守卫处理动态条件
当你下次面对一堆 else if 链时,不妨停下来想想:这段逻辑是否可以用 switch 表达式重写?往往你会发现,代码不仅更短,而且意图更清晰——这才是现代 C# 的优雅之道。