1. 入门
你已经会写这样的代码了:
switch (color)
{
case "red":
Console.WriteLine("停!");
break;
case "yellow":
Console.WriteLine("请等待...");
break;
case "green":
Console.WriteLine("可以走了!");
break;
default:
Console.WriteLine("这是什么颜色?");
break;
}
但如果我们想根据输入参数给变量赋不同的值,比如从函数里返回一个基于数字的字符串呢?在 switch-表达式 出现之前,只能写成这样:
string meaning;
switch (number)
{
case 42:
meaning = "生命、宇宙以及一切的终极答案";
break;
case 7:
meaning = "幸运数字";
break;
default:
meaning = "普通数字";
break;
}
感觉对21世纪的语言来说有点不优雅,对吧?我们更想直接返回值,就像函数式语言那样。
这时候 switch-表达式 就登场了 —— 这是C# 8.0起最酷(也最新)的特性之一。
2. switch-表达式:让人想抱一抱的语法
对比:语句和表达式
经典的 switch 是 statement(“语句”),而 switch-表达式 是 expression,也就是它会计算出一个值,可以直接赋给变量或者 return。
switch-表达式的结构:
var result = value switch
{
pattern1 => expression1,
pattern2 => expression2,
_ => defaultExpression // “下划线”就是“否则”
};
比如:
int number = 42;
string meaning = number switch
{
42 => "生命、宇宙以及一切的终极答案",
7 => "幸运数字",
_ => "普通数字"
};
Console.WriteLine(meaning); // => 生命、宇宙以及一切的终极答案
很简洁、可读,没有一堆代码,也没有 break;。
注意: 下划线 _ 就是“匹配所有剩下的情况”,等价于 default。
3. switch-表达式 和 pattern:怎么配合用
这才是真正的乐趣开始。在 switch-表达式 里,不光能用普通值,还能用 pattern:比如区间判断、类型判断、对象属性判断、解构(把对象拆成部分),甚至还能用 combinatorial patterns(and、or、not)。
switch-表达式里的 pattern 示例
常量 pattern
就是我们上面做的那种:和 42、7 等等比较。
区间和比较
int age = 17;
string category = age switch
{
< 18 => "未成年人",
>= 18 and <= 65 => "成年人",
> 65 => "老年人",
_ => "未知年龄段"
};
Console.WriteLine(category);
顺便说一句 —— 可以一起用多个条件!C# 越来越有表现力了。
类型 pattern (Type Patterns)
比如我们有个对象,类型可能不同(比如 object value;)。我们可以这样处理不同类型:
object value = 3.14;
string description = value switch
{
int i => $"整数: {i}",
double d => $"小数: {d:F2}",
string s => $"这是字符串: '{s}'",
null => "null!",
_ => "其他类型"
};
Console.WriteLine(description); // => 小数: 3.14
属性 pattern 和位置 pattern (Property Patterns 和 Positional Patterns)
从 C# 8 开始,我们可以直接在 switch-表达式 里判断属性值。
对象示例
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
User user = new User { Name = "安娜", Age = 17 };
string welcome = user switch
{
{ Age: < 18 } => $"你好, {user.Name}! 你是青少年。",
{ Age: >= 18 and <= 65 } => $"嗨, {user.Name}! 成年生活很棒。",
{ Age: > 65 } => $"欢迎, {user.Name}! 永远欢迎你。",
_ => "未知年龄"
};
Console.WriteLine(welcome);
这里大括号里的 { Age: < 18 } 是 property pattern,也就是只判断对象的某个属性。
4. C# 11-14 新 pattern
C# 越来越简洁灵活。最近加了 combinatorial patterns:and、or、not,还有更强的 positional patterns。我们来看看。
逻辑 pattern:and、or、not
你可以像写逻辑表达式那样组合条件!
int temperature = 25;
string result = temperature switch
{
< 0 => "很冷!",
>= 0 and < 20 => "有点凉",
>= 20 and < 30 => "很舒服",
>= 30 or <= -30 => "极端!",
_ => "奇怪的温度"
};
如果想排除某些情况,也可以:
int score = 80;
string grade = score switch
{
>= 90 => "优秀",
>= 60 and not >= 90 => "良好",
_ => "差"
};
解构 (Positional Patterns)
如果你有 struct 或 record,支持解构,C# 允许你在 switch-表达式 里直接拆对象:
public record Point(int X, int Y);
Point p = new Point(10, 20);
string desc = p switch
{
(0, 0) => "原点",
(var x, 0) => $"在X轴上, X={x}",
(0, var y) => $"在Y轴上, Y={y}",
(var x, var y) when x == y => $"在对角线: {x}",
_ => $"在点 ({p.X}, {p.Y})"
};
Console.WriteLine(desc); // => 在点 (10, 20)
5. 什么时候用 switch-表达式,为什么用
在现代C#里,switch-表达式 不只是个“新潮玩意”,而是真正能帮你少写废话,让代码更紧凑、更好测、更好维护的利器。写 parser、命令处理、业务逻辑、规则配置等场景,尤其是需要根据复杂条件分支(不仅仅是值,还有类型、区间、属性、组合)时特别有用。
面试时
- 你会怎么处理用户的不同回答?
- 怎么让函数根据类型和值返回不同结果?
- 怎么优雅地加新规则,不用一堆 if-else?
秀一个带 pattern 的 switch-表达式!这立马能体现你对新特性的掌握和你的代码风格。
表格:switch 语句 vs switch-表达式
| 特点 | switch statement | switch expression |
|---|---|---|
| 类型 | 语句 (statement) | 表达式 (expression) |
| 需要 break | 必须 | 不需要 |
| 能否返回值 | 只能通过变量 | 可以直接返回值 |
| 能否用 pattern | 部分支持 | 完全支持(类型、属性等) |
| 坑点 | 容易忘 break | 所有分支都要返回值 |
6. 常见错误和小坑
- 新手经常搞混 switch 语句("statement")和 switch-表达式("expression")。比如忘了 switch-表达式 不需要 break;,而且每个分支都必须返回值。
- 如果忘了写 _ 分支,编译器会提醒你:“那如果都不匹配呢?”
- switch-表达式 里不能用 goto(这其实挺好!)。
- 如果有重复的条件(比如两个一样的 pattern),编译器也不会放过你。
- 注意 switch-表达式 返回值的类型:它必须和你赋值的变量类型兼容。
GO TO FULL VERSION