导读:本期聚焦于小伙伴创作的《C#中模式匹配到底该怎么用?从基础到高级实战讲解》,敬请观看详情。还在为C#里一堆if else类型判断写得又臭又长而头疼吗?模式匹配就是专门解决这类问题的语法糖。它允许你把类型判断、属性解构、条件过滤写进switch和is表达式里,让分支逻辑既安全又直观。本文从is类型模式讲起,逐步覆盖switch表达式、属性模式、元组模式以及递归模式,配合可运行代码片段说明每种写法的适用场景与性能特征。读完你就能把旧式类型转换代码重构成简洁稳健的现代C#写法,减少强制转换异常并提升可读性。

模式匹配是C# 7.0之后逐步引入并在后续版本中不断增强的语言特性,它让开发者可以用声明式的方式对变量的类型、结构和值进行检查与提取。传统写法里我们常先用is判断类型,再强制转换,最后读属性;模式匹配把这些步骤压缩进一个表达式,既减少临时变量,也避免转换失败导致的运行时异常。

C#中模式匹配到底该怎么用?从基础到高级实战讲解

一、is类型模式与声明模式

最基础的用法是is类型模式,它可以在判断对象类型的同时声明一个新变量,如果匹配成功该变量自动完成转换,作用域仅限于后续逻辑块。相比先写if (obj is string)再(string)obj的写法,声明模式少一次类型转换操作,也避免了转换与判断不一致的风险。

下面代码展示如何用is模式处理一个未知类型的集合元素。注意当匹配失败时不进入分支,变量也不会被赋值,因此不存在空引用或无效转换问题。

object data = "hello pattern";

if (data is string text)
{
    Console.WriteLine("字符串长度为: " + text.Length);
}
else if (data is int number)
{
    Console.WriteLine("整数平方为: " + (number * number));
}
else
{
    Console.WriteLine("未知类型");
}

声明模式也支持常量模式,例如data is null或data is 0,编译器会优化成对应的相等判断。在热路径上这种写法比调用Equals方法略快,同时语义更清楚。

当只需要判断而不需要提取值时,可以直接写is类型不加变量名。但多数业务场景下我们更关心内容,因此声明模式使用频率更高。

二、switch表达式与类型模式

C# 8.0引入的switch表达式把传统switch语句变成可返回值的表达式,配合类型模式可以替代复杂的if else链。它要求覆盖所有情况或使用弃元模式_兜底,编译器会检查完整性,漏写分支会在编译期报错。

以下示例用switch表达式计算不同形状的面积。每个case都是一个模式,右侧是表达式主体,整体返回一个double。这种写法没有break,也不会意外穿透,比语句版switch安全得多。

abstract class Shape { }
class Circle : Shape { public double Radius { get; set; } }
class Rectangle : Shape { public double Width { get; set; } public double Height { get; set; } }

double Area(Shape shape) => shape switch
{
    Circle c => Math.PI * c.Radius * c.Radius,
    Rectangle r => r.Width * r.Height,
    null => 0,
    _ => throw new ArgumentException("未知形状")
};

switch表达式的求值顺序自上而下,第一个匹配的模式生效。因此具体类型要写在通用类型之前,否则会被宽泛模式拦截。若把_放在最前,后面所有分支都成了死代码,编译器会给出警告。

在需要多个条件组合时,可以在模式后加when子句做额外过滤。when内部可以使用任意布尔逻辑,但过于复杂的when会降低可读性,此时建议拆分成独立方法。

三、属性模式与位置模式

属性模式允许在switch中直接解构对象的属性并匹配具体值。比如对包含X、Y坐标的点做区域判断,旧写法要反复访问point.X,属性模式则把条件内联,逻辑一目了然。

下面代码用属性模式识别坐标系中的象限。每个分支同时检查X和Y的符号,匹配成功才执行对应表达式,不需要手动写逻辑与运算。

class Point { public int X { get; set; } public int Y { get; set; } }

string Quadrant(Point p) => p switch
{
    { X: > 0, Y: > 0 } => "第一象限",
    { X: < 0, Y: > 0 } => "第二象限",
    { X: < 0, Y: < 0 } => "第三象限",
    { X: > 0, Y: < 0 } => "第四象限",
    { X: 0, Y: 0 } => "原点",
    _ => "坐标轴上"
};

位置模式依赖Deconstruct方法,把对象拆成有序参数再匹配。它适合元组式数据结构,写起来比属性模式更紧凑,但要求类型显式提供解构函数,否则编译失败。

属性模式与位置模式可以嵌套。例如匹配一个圆且半径大于十的情况,可写成Circle c and { Radius: > 10 },逻辑与用and连接,或用or表示多选,这种组合在验证输入时非常实用。

四、元组模式与递归模式

元组模式直接对多个值做联合匹配,常用于游戏状态机或权限判断。它不需要定义新类型,用括号包住多个变量即可,编译器会生成高效的相等比较。

以下例子根据角色与等级返回不同提示。两个维度同时参与匹配,分支清晰,比嵌套if更易维护。

string GetTip(string role, int level) => (role, level) switch
{
    ("admin", >= 10) => "高级管理员",
    ("admin", _) => "普通管理员",
    ("user", >= 5) => "活跃用户",
    ("user", _) => "新用户",
    _ => "访客"
};

递归模式指模式本身可以包含子模式,例如列表模式匹配数组首个元素。C#对列表模式的支持让处理集合头部变得直观,可以用来写简单的解析器或命令分发器。

看一段匹配数组开头内容的代码。模式["get", var path]表示数组第一个元素是字符串get,第二个元素捕获到path变量,长度不符则不匹配。这种写法替代了手工索引访问,越界风险交由编译器处理。

string Parse(string[] cmd) => cmd switch
{
    ["get", var path] => "读取: " + path,
    ["set", var path, var val] => "写入: " + path + "=" + val,
    [] => "空命令",
    _ => "未知命令"
};

五、性能与最佳实践

模式匹配在编译期大多被翻译成常规类型判断与虚方法调用,没有反射开销。is声明模式比is加转换少一次类型检查,在循环内可观察到微小但稳定的提升。switch表达式生成的IL通常比等价if链更紧凑。

使用时应注意不要在一个switch里堆砌十几条带when的复杂分支,那样会抵消可读性优势。当业务逻辑庞大时,可把部分模式逻辑抽到独立函数,或用字典委托替代。另外,对值类型使用模式匹配不会产生装箱,对引用类型也只是普通判等,不必担心隐藏分配。

最后建议从局部重构开始,把最啰嗦的if else块改成switch表达式,再逐步引入属性与元组模式。团队统一风格后,代码评审成本会明显下降,新成员也能更快理解分支意图。

C#_Pattern_Matchingswitch表达式类型模式修改时间:2026-08-09 18:09:43

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。