switch表达式必须返回值,是结果导向的;需覆盖所有可能路径,支持类型匹配+when守卫,不可fall-through,null和_兜底需显式处理,不适用于副作用或条件耦合场景。

Switch表达式必须返回值,不能只“做事情”
传统 switch 语句是“动作导向”的:匹配后执行一段逻辑,比如调用方法、修改变量、break 跳出。而 switch 表达式是“结果导向”的——它本身就是一个值,必须为每个分支提供一个返回结果,编译器会强制你填满所有可能路径。
- 写成语句却没返回值?编译直接报错:
CS8506: No best type was found for the switch expression - 漏掉
_ => ...兜底?如果输入类型或范围无法被穷举(比如int),编译器会警告甚至报错:CS8509: The switch expression does not handle all possible values - 想在某个分支里
Console.WriteLine然后“啥也不返”?不行。得包装成表达式,例如:() => { Console.WriteLine("log"); return "done"; },但这就违背简洁初衷了
类型匹配 + when 守卫是核心能力,别只当“高级if”用
新版 switch 表达式真正拉开差距的地方,不是语法短,而是能一次性完成「类型判断 + 变量绑定 + 条件过滤」三件事。传统写法要靠 is + as + if 套娃,容易出空引用或重复转换。
- 错误示范(传统):
if (obj is string s && s.Length > 0) { ... } else if (obj is int i && i > 100) { ... } - 正确写法(表达式):
obj switch { string s when s.Length > 0 => $"非空字符串:{s}", int i when i > 100 => $"大整数:{i}", _ => "其他" } - 注意:
when后面是任意布尔表达式,可访问绑定的变量(如s、i),但不能捕获外部作用域中同名变量(会遮蔽) - 枚举组合模式很实用:
day switch { DayOfWeek.Saturday or DayOfWeek.Sunday => "休息日", _ => "工作日" }
从传统 switch 语句升级时,最常踩的三个坑
不是把 {} 换成 => 就算升级成功。结构差异导致行为隐性变化,稍不注意就引入 bug。
-
break 消失了,但“顺序执行”也消失了:传统
case漏写break会 fall-through;表达式里根本没这概念——每个分支完全独立,不存在穿透,所以别试图复刻“多个 case 共享逻辑” -
null 不再需要单独判空:
null是合法的常量模式,可直接写null => "空值",不用再担心obj?.ToString()或提前if (obj == null) -
默认分支必须显式写
_ => ...:不能省略,也不能用default(那是语句语法)。下划线_是弃元模式,表示“其余所有未匹配情况”,它是编译器做穷尽检查的关键依据
什么时候该坚持用 if-else,而不是硬套 switch 表达式
不是所有多分支都适合 switch 表达式。它强在「输入明确、输出单一、分支互斥」的映射场景。一旦条件耦合外部状态、有副作用、或分支逻辑严重不对称,强行改会造成可读性下降。
- 适合:
httpStatusCode switch { 200 => "OK", 404 => "Not Found", _ => "Error" } - 不适合:
user switch { var u when u.IsAdmin && DateTime.Now.Hour SendMorningReport(), ... }—— 时间依赖、副作用、逻辑混杂,不如拆成清晰的if - 性能无差别:编译后都是跳转表或二分查找,不用为“哪个更快”纠结;但表达式更易被 JIT 优化为只读数据流
- 兼容性注意:C# 8.0+ 才支持,项目若还在用 .NET Framework 4.7.2 或旧版 SDK,得先确认语言版本
最易被忽略的一点:switch 表达式的类型推导是“所有分支返回值的最近公共基类/接口”。如果有的分支返回 string,有的 throw 异常,有的返回 int,编译器可能推成 object 或报错——这时候显式声明目标类型反而更稳,比如 string result = value switch { ... };


















