C#.Net筑基-模式匹配汇总

01、模式匹配概述
从C#7开始支持的 模式匹配 语法(糖,挺甜),可非常灵活的对数据进行条件匹配和提取,经过多个版本的完善,已经非常强大了。
C# 支持多种模式,包括声明、类型、常量、关系、属性、列表、var 和弃元等,在is、switch语句、switch表达式中使用,还可以使用布尔逻辑关键字 and、or 和 not 组合多个模式,极大的简化了代码编写,可读性也还不错。
| 标题 | 说明 | 示例/备注 |
|---|---|---|
| 类型和声明模式 | 如果类型兼容,则申明并赋值变量 | if (age is int i) |
| 常量模式 | 检查表达式值是否等于、不等于(not)常量值 | if(age is null || age is 0) |
关系模式>< |
使用关系运算符<、>、<= 或 >=匹配 |
case 0 or <=6 |
| 逻辑模式 | 用not>and >or连接多个模式表达式 |
case < 12 and ( >6 or 6) |
属性模式{:} |
对实例的属性、字段进行模式匹配:{属性/字段:匹配模式} |
if (b is { Year: < 2000, Month: 1 or 11 }) |
| 位置模式(解构) | 基于解构赋值进行模式匹配:(解构参数) |
if(point is (_,>0,>0)) |
| var 模式 | 用var申明(捕获)任意局部变量 |
if(point is var p && p.X>0) |
| 弃元模式_ | 弃元模式 _ 来匹配任何(其他)表达式 |
表示不要的 |
| 列表模式[] | 对数组(列表)进行匹配,在中括号[]中匹配列表中的项 |
if(numbers is [_, 2, 3, ..]) |

模式匹配基本都是语法糖,味道都不错!C#在编译时会输出原本的基础代码,可通过 https://sharplab.io/ 在线查看编译后的代码。
02、模式匹配
2.1、类型和声明模式
检查类型是否匹配,同时申明变量,如果类型兼容则申明并赋值变量,该变量在后面代码作用域中有效。
object age = "123";
if (age is int i) //类型匹配+申明变量i
{
Console.WriteLine($"age1 = {i}");
}
switch (age)
{
case string: //类型匹配
Console.WriteLine($"type is string");
break;
case int iage: //类型匹配+申明变量iage
Console.WriteLine($"age2 = {iage}");
break;
}
//上面is语句编译后的代码效果:
if (obj is int)
{
int value = (int)obj;
}
2.2、常量模式
检查表达式值是否等于、不等于(not)常量值,常量值包括字面量常量,也包括const常量值。传统的Switch语句就是常量模式匹配。
object age = null;
if (age is not null && age is 100) //age is 100 等同于 age is int && (int)age==100
{
Console.WriteLine($"age1 = {age}");
}
var type = age switch{
1 or 2 or 3=>"婴儿",
4 => "幼儿",
null or not 5 => "unknow",
_=>"",
};
2.3、关系模式><
用关系运算符来匹配表达式,就是对常量数值进行大小比较运算,使用关系运算符<、>、<= 或 >=,多个表达式可用and、or连接,当然也支持括号。
object age = 6;
if (age is int n and >= 6)
{
Console.WriteLine("666");
}
switch (age)
{
case 0 or <=6:
Console.WriteLine("幼儿");
break;
case < 12 and ( >6 or 6):
Console.WriteLine("青少年");
break;
}
2.4、逻辑模式not/and/or
用 not、and 和 or 模式连结符来创建逻辑模式,连接多个模式表达式。
- 优先级顺序:
not>and>or。 - 推荐使用
(括号)显示控制优先顺序,可读性更好。
object age = 6;
if (age is int n and (not 6 or >5) )
{
Console.WriteLine("666");
}
2.5、属性模式{:}
对实例的属性、字段进行模式匹配,可以嵌套其他模式匹配,非常的强大,属性匹配用大括号来包装{属性/字段:匹配模式}。
- 多个属性/字段都匹配为
true时,最终才会匹配成功。 - 可以结合类型申明模式使用。
- 可嵌套使用,会递归匹配。
DateTime birthday = new DateTime(1999, 11, 12);
if (birthday is { Year: < 2000, Month: 1 or 11 })
{
Console.WriteLine("年龄、星座不合适");
}
//嵌套使用
public record Point(int X, int Y);
public record Segment(Point Start, Point End);
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start: { Y: 0 } } or { End: { Y: 0 } };
static bool IsAnyEndOnXAxis(Segment segment) =>
segment is { Start.Y: 0 } or { End.Y: 0 };
2.6、位置模式(解构)
基于解构赋值进行模式匹配:
Tuple、record 和 DictionaryEntry是内置支持解构的,关于解构赋值可参考相关内容。- 用括号
()报装,这也是 解构(Deconstruct)的语法形式。 - 可以嵌套其他模式匹配,如常量、关系、逻辑、属性模式等。
void Main()
{
Point point = new Point("sam", 12, 13);
var len = point switch
{
//类型匹配、属性模式、位置模式:Name属性必须为string,且长度为0,X、Y值为0
(string { Length: <= 0 }, 0, 0) => 0,
(_, > 0, 0) => point.X, //X值大于0,Y值为0
(_, 0, > 0) => point.Y, //Y值大于0,X值为0
(_, 10 or > 10, 10 or > 10) p => p.X * p.Y,
_ => 0,
};
}
public record Point(string Name, int X, int Y);
2.7、var 模式
用var申明(捕获)任意局部变量,把表达式的结果分配给var临时变量。算是类型模式的变种,将类型名替换成了var。
void Main()
{
Point point = new Point("sam", 12, 13);
if(point is var p && p.X>0 && p.Y>0){ //is var
Console.WriteLine("OK");
}
var len = point switch
{
var (_,x,y) when x>0 && y>0 => true,// var
};
}
public record Point(string Name, int X, int Y);
2.8、弃元模式_
弃元模式(Discard Pattern),字面理解就是被遗弃、没人要的。可以将弃元模式看做是一个占位符,表示一个没人用的变量,可匹配任意类型,用来简化代码。语法是用下划线“_”表示。
常用场景:
- 1、解构时的占位符。
- 2、在
Switch中匹配任意其他模式,类似default的作用。 - 3、在
out参数中占位,表示一个没人用的out参数。 - 4、独立弃元,接收无用的表达式输出。
var tuple = new Tuple<int, int>(3, 4);
var (x, _) = tuple; //1、只需要第一个参数,其他就用“_”来占位
Console.WriteLine(x); //3
_= x switch
{
2 or <2 => "small",
int and <18=>"young",
_=>"other", //2、匹配其他模式,效果同default
};
int.TryParse("", out _); //3、不用的out变量,实际上是申明了变量的
async void Print(object arg)
{
_ = arg ?? throw new ArgumentException(); //4、接收无用的返回,效果同下
if (arg == null) throw new ArgumentException();
_ = Task.Run(()=>Console.WriteLine("task run")); //接收一个不用的返回
}
弃元模式_是一个提供给编译器用的符号,告诉编译这个变量不用了,编译器会根据情况进行优化处理。在对out参数使用时,编译器会自动创建变量,如下代码:
int.TryParse("",out _);
//实际编译后的代码如下
int result;
int.TryParse("", out result);

需要注意的是 下划线
_是并不是一个关键字,也能当做参数名来使用,不要混用。
2.9、列表模式[]
C#11支持的,对数组(列表)进行匹配,在中括号[]中匹配列表中的项。
- 跳过的项可以用弃元模式
_。 - 可以用数组的切片模式匹配开头、结尾的元素。
void Main()
{
int[] numbers = { 1, 2, 3, 4 };
Console.WriteLine(numbers is [_, 2, 3, ..]); // True
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]); // False
}
03、模式匹配应用
上面的各种模式匹配主要就用在 is 运算符、switch 语句、switch 表达式 中。

3.1、is运算符
is 运算符 本来主要是用来检测类型兼容性的,加上模式匹配就能玩出各种花样了,极大简化了让各种检查类的代码。
object value = 12;
if (value is int && value is not null) //is类型检测+逻辑模式
{
Console.WriteLine(value);
}
if (value is int a && a > 6) //+申明模式
{
Console.WriteLine(a);
}
if (value is int age and > 10 and < 14) //关系模式
{
Console.WriteLine(age);
}
var user = new { Name = "sam", Age = 12 };
if (user is { Name: _, Age: > 10 }) //属性模式
{
Console.WriteLine(user.Name);
}
int[] arr = new int[] { 1, 2, 3 };
if (arr is [> 0, ..]) //列表模式:第一个元素>0
{
Console.WriteLine(arr);
}
var dt = new Tuple<string, int>("sam", 100);
if (dt is (_, > 60) d) //位置模式+申明模式(好像没什么用)
{
Console.WriteLine(d.Item1);
}
3.2、switch..case语句
switch..case 语句 是很多语言中都有的基本多条件分支语句,传统的 case 只能用于匹配常量,多用于枚举。
case不能穿透,一个case执行完后必须break结束,或者return返回(退出方法),可以多个case匹配执行一组逻辑代码。- 传统的
case就是常量模式,而现代的case可以结合上面多种模式使用,非常强大。 - 加
when,自由附加更多条件。
int age = 22;
string sex = "Male";
switch (age)
{
case 1:
case 2:
Console.WriteLine("婴儿");
break;
case <= 3:
Console.WriteLine("幼儿");
break;
case > 10 and < 16:
Console.WriteLine("青少年");
break;
case > 18 when sex == "Male":
Console.WriteLine("成年男性");
break;
case int:
break;
}
3.3、switch表达式
C#8中switch有了新的语法 —— switch 表达式 ,可以看做是switch..case语句的一个变种,使用比较类似。switch表达式是一个赋值(输出)语句。
=>左侧为模式(返回一个bool),如果模式匹配(true)则返回右侧的值,最后一个弃元模式匹配其他情况,同default效果。
int type = 6;
var message = type switch
{
<= 1 => "success",
2 => "warning",
3 => "error",
> 3 and < 10 => "other error",
_ => "unkonwn error",
};
可以用when来进行更多的判断,when后面的表达式就很自由了,只要返回boo即可。
object type = 6;
var message = type switch
{
int i when i<6 => "ok",
string s when s=="null"=>"Null",
string s when !string.IsNullOrEmpty(s)=>"string value",
_=>"unknown value"
};
Console.WriteLine(message);
支持多个变量的组合模式:用括号()包含多个变量
string gender = "male";
int age = 10;
string type = (gender,age) switch{
("male",>18)=>"VIP",
(not "male",>26 and <35)=>"VVIP",
_=>"",
};
参考资料
️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀
C#.Net筑基-模式匹配汇总的更多相关文章
- Oracle 12c 的新功能:模式匹配查询
模式匹配SQL 在一系列的数据行中辨识出某种模式是一种广泛需求的功能,但在以前的SQL中是不可能的.有许多解决方法,但这些都很难写,很难理解,而且执行效率低下.在Oracle数据库中,从12c开始,你 ...
- awk文本处理知识汇总
参考资料:http://man.linuxde.net/awk http://www.cnblogs.com/chengmo/archive/2013/01/17/2865479.html http: ...
- shell脚本语法基础汇总
shell脚本语法基础汇总 将命令的输出读入一个变量中,可以将它放入双引号中,即可保留空格和换行符(\n) out=$(cat text.txt) 输出1 2 3 out="$(cat te ...
- Java 8 学习资料汇总【转载】
原文地址 2014年3月18日,Java SE 8 发布,而 Java 9 预期2016年发布: 2011年7月7日,Java 7 发布,是2009年4月20日被Oracle 以74亿美元收购首次推出 ...
- scala 系列文章汇总
本文作为scala系列文章索引 本博客目录: case class 背后的秘密 以spark源码为参照分析模式匹配及种类 另外,本文还收录了几个作者认为比较好的博文或网站: scala 相关网址汇总 ...
- 为什么说JAVA中要慎重使用继承 C# 语言历史版本特性(C# 1.0到C# 8.0汇总) SQL Server事务 事务日志 SQL Server 锁详解 软件架构之 23种设计模式 Oracle与Sqlserver:Order by NULL值介绍 asp.net MVC漏油配置总结
为什么说JAVA中要慎重使用继承 这篇文章的主题并非鼓励不使用继承,而是仅从使用继承带来的问题出发,讨论继承机制不太好的地方,从而在使用时慎重选择,避开可能遇到的坑. JAVA中使用到继承就会有两 ...
- C# 语言历史版本特性(C# 1.0到C# 7.1汇总更新) C#各版本新特性 C#版本和.NET版本以及VS版本的对应关系
C# 语言历史版本特性(C# 1.0到C# 7.1汇总更新) 2017年08月06日 11:53:13 阅读数:6705 历史版本 C#作为微软2000年以后.NET平台开发的当家语言,发展至今具有1 ...
- Java常用英语汇总(面试必备)
Java常用英语汇总(面试必备) abstract (关键字) 抽象 ['.bstr.kt] access vt.访问,存 ...
- 老猿Python博文汇总目录--按标题排序
☞ ░ 前往老猿Python博文目录 ░ 本部分为老猿CSDN全部博文的汇总(含转载部分),所有文章在此未进行归类,仅按文章标题排序,方便关键字查找.本部分内容将至少以周为单位定期更新,可能不包含发布 ...
- 常用 Gulp 插件汇总 —— 基于 Gulp 的前端集成解决方案(三)
前两篇文章讨论了 Gulp 的安装部署及基本概念,借助于 Gulp 强大的 插件生态 可以完成很多常见的和不常见的任务.本文主要汇总常用的 Gulp 插件及其基本使用,需要读者对 Gulp 有一个基本 ...
随机推荐
- #树套树,二维线段树#HDU 4819 Mosaic
题目 多组数据,给定一个\(n*n\)的矩阵(\(n\leq 80,a_{i,j}\leq 10^9\)) 多组询问一个以\((x,y)\)为中心,边长为\(L\)的子矩阵最大值\(mx\)和最小值\ ...
- #线段树,组合计数,二项式定理#CF266E More Queries to Array
洛谷传送门 CF266E传送门 分析 首先区间修改区间查询首选线段树 要找突破口,\((i-l+1)^k\)中\(i\)不是定值, 显然得拆开,而且\(k\)很小,根据二项式定理, \[\sum_{i ...
- Health Kit接入资质要求详解,开发不迷路!
开发运动/健康应用过程中,需要使用Health Kit提供的数据能力,作为独立的个人开发者或是企业开发者,接入时分别需要满足什么样的条件呢? 个人开发者接入资质审核要求 •个人开发者应用需上架至华为应 ...
- vue3 快速入门系列 —— vue3 路由
vue3 快速入门系列 - vue3 路由 在vue3 基础上加入路由. vue3 需要使用 vue-router V4,相对于 v3,大部分的 Vue Router API 都没有变化. Tip:不 ...
- TensorRT C# API 项目更新 (1):支持动态Bath输入模型推理
1. 项目介绍 NVIDIA TensorRT 是一款用于高性能深度学习推理的 SDK,包括深度学习推理优化器和运行时,可为推理应用程序提供低延迟和高吞吐量.基于 NVIDIA TensorRT ...
- React中的setState执行机制
一.是什么 一个组件的显示形态可以由数据状态和外部参数所决定,而数据状态就是state 当需要修改里面的值的状态需要通过调用setState来改变,从而达到更新组件内部数据的作用 如下例子: impo ...
- 用百度和神策做埋点为何pv差异很大?
近期ClkLog收到一个客户反馈说我们与百度统计的PV数据差异很大.为了验证问题,开发进行了一次对页面浏览量统计的测试.针对同一个IP同一个时间的页面浏览量统计发现,百度的统计数据只有一条,而ClkL ...
- 力扣607(MySQL)-销售员(简单)
题目: 表: SalesPerson 表: Company 表: Orders 编写一个SQL查询,报告没有任何与名为 "RED" 的公司相关的订单的所有销售人员的姓名. 以 任意 ...
- 力扣138(java)- 复制带随机指针的链表(中等)
题目: 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点. 构造这个链表的 深拷贝. 深拷贝应该正好由 n 个 全新 节点组成,其 ...
- Java 应用压测性能问题定位经验分享
简介: 问题千千万,但只要修练了足够深厚的内功,形成一套属于自己的排查问题思路和打法,再加上一套支撑问题排查的工具,凭借已有的经验还有偶发到来的那一丝丝灵感,相信所有的问题都会迎刃而解. 作者:凡勇 ...