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

01、模式匹配概述

C#7开始支持的 模式匹配 语法(糖,挺甜),可非常灵活的对数据进行条件匹配和提取,经过多个版本的完善,已经非常强大了。

C# 支持多种模式,包括声明、类型、常量、关系、属性、列表、var 和弃元等,在isswitch语句、switch表达式中使用,还可以使用布尔逻辑关键字 andornot 组合多个模式,极大的简化了代码编写,可读性也还不错。

标题说明示例/备注
类型和声明模式如果类型兼容,则申明并赋值变量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#在编译时会输出原本的基础代码,可通过 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: //类型匹配+申明变量iageConsole.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、关系模式><

用关系运算符来匹配表达式,就是对常量数值进行大小比较运算,使用关系运算符<><=>=,多个表达式可用andor连接,当然也支持括号。

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

notandor 模式连结符来创建逻辑模式,连接多个模式表达式。

  • 优先级顺序: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 varConsole.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);

image.png

📢需要注意的是 下划线_是并不是一个关键字,也能当做参数名来使用,不要混用。

2.9、列表模式[]

C#11支持的,对数组(列表)进行匹配,在中括号[]中匹配列表中的项。

  • 跳过的项可以用弃元模式_
  • 可以用数组的切片模式匹配开头、结尾的元素。
void Main()
{int[] numbers = { 1, 2, 3, 4 };Console.WriteLine(numbers is [_, 2, 3, ..]);        // TrueConsole.WriteLine(numbers is [0 or 1, <= 2, >= 3]); // False
}

03、模式匹配应用

上面的各种模式匹配主要就用在 is 运算符、switch 语句、switch 表达式 中。

image.png

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#8switch有了新的语法 —— 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",_=>"",
};

参考资料

  • 模式匹配 - 模式中的 is 和 switch 表达式,以及 and、or 和 not 运算符
  • 析构元组和其他类型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/61120.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python蓝桥杯刷题1

1.确定字符串是否包含唯一字符 题解&#xff1a;调用count函数计算每一个字符出现的次数&#xff0c;如果不等于1就输出no&#xff0c;并且结束循环&#xff0c;如果等于1就一直循环直到计算到最后一个字符&#xff0c;若最后一个字符也满足条件&#xff0c;则输出yes import…

Javascript进阶——面试常见

以下是对前端JS面试题的详细回答&#xff1a; 1. 对 fetch 的理解及其优缺点 fetch 是一个基于 Promise 的&#xff0c;用于浏览器和服务器之间进行数据交换的 API。它提供了一个简洁的接口来请求资源。 优点&#xff1a; 语法简洁&#xff1a;fetch 的语法更加简洁&#x…

Unity类银河战士恶魔城学习总结(P127 Stat ToolTip属性提示)

【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址&#xff1a;https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了把鼠标放到属性上面就会显示属性的作用 UI_StatToolTip.cs 这段代码实现了一个UI提示框&#xff08;ToolTip&#xff09;功能…

计算机编程中的事件驱动编程模型及其在构建响应式用户界面中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 计算机编程中的事件驱动编程模型及其在构建响应式用户界面中的应用 计算机编程中的事件驱动编程模型及其在构建响应式用户界面中…

django-ninja 实现cors跨域请求

要在Django-Ninja项目中实现跨域&#xff08;CORS&#xff09;&#xff0c;你可以使用django-cors-headers库&#xff0c;这是一个专门用于处理跨域资源共享&#xff08;CORS&#xff09;问题的Django应用程序。以下是具体的步骤和配置&#xff1a; 安装依赖&#xff1a; 使用p…

ROS第九梯:ROS+VSCode+Python+C++自定义消息发布和订阅

首先,Python版本的ROS项目和C++版本的ROS项目前期创建功能包的步骤基本一致,具体可参考第二章。 费一步:新建msg文件 在功能包(data_input)目录下创建一个msg文件夹,并在msg文件夹下创建一个名为Box的msg文件,具体如下图所示: 该msg文件为一个用于描述3D Box的文件,…

selenium元素定位---元素点击交互异常解决方法

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、异常原因 在编写ui自动化时&#xff0c;执行报错元素无法点击&#xff1a;ElementClickInterceptedException 具体报错&#xff1a;selenium.common.exc…

Front Panel Window Bounds 与 Front Panel Window Bounds 的区别与应用

在LabVIEW中&#xff0c;Front Panel Window Bounds 和 Front Panel WindowBounds 是两个不同的属性节点&#xff0c;用于描述前面板窗口的位置和大小。它们的区别主要体现在它们表示的是窗口的不同部分&#xff0c;具体如下&#xff1a; 1 Window Bounds&#xff1a;调整整个…

H.265流媒体播放器EasyPlayer.js播放器出现加载视频等待画面时长过长的原因排查

在数字媒体时代&#xff0c;用户体验是衡量播放器性能的关键指标之一。EasyPlayer.js网页web无插件播放器作为一款流行的Web视频播放器&#xff0c;其加载速度和响应时间直接影响着用户的观看体验。 1、问题描述 加载视频等待画面时长过长。 2、可能的原因&#xff1a; 检查下…

计算机网络-MSTP基础实验一(单域多实例)

前面我们已经大致了解了MSTP的基本概念和工作原理&#xff0c;但是我自己也觉得MSTP的理论很复杂不结合实验是很难搞懂的&#xff0c;今天来做一个配套的小实验以及一些配置命令。 一、网络拓扑 单域多实例拓扑 基本需求&#xff1a;SW1为VLAN10的网关&#xff0c;SW2为VLAN20的…

大数据-227 离线数仓 - Flume 自定义拦截器(续接上节) 采集启动日志和事件日志

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇开始了&#xff01; 目前开始更新 MyBatis&#xff0c;一起深入浅出&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff0…

windows系统中实现对于appium的依赖搭建

Node.js&#xff1a;Appium是基于Node.js的&#xff0c;因此需要安装Node.js。可以从Node.js官网下载并安装。 Java Development Kit (JDK)&#xff1a;用于Android应用的自动化测试&#xff0c;需要安装JDK。可以从Oracle官网下载并安装。 Android SDK&#xff1a;进行Andro…

【langchain4j】AIservices能够实现更加灵活的chain

文章目录 AI service介绍如何工作的AiServices提供的能力支持的返回形式 简单的例子&#xff1a;接收用户消息&#xff0c;并按规定返回接收单个变量接收更多动态变量 advanced RAGChaining multiple AI Services&#xff1a;多个AiSerives合并到一起相关教程&#xff1a;[Lang…

蓝桥杯某例题的解决方案和拓展(完全能解决例题本身)

蓝桥杯题目&#xff1a;求1&#xff08;包含&#xff09;直到20230408&#xff08;包含&#xff09;所有自然数的加和。 这个题比较恶心的一点在于&#xff0c;20230408本身没有超过int的上限&#xff0c;但是它的加和是超过int上限的&#xff0c;因此如果直接用int来计算&…

Ubuntu24.04安装gpfs客户端

文章目录 Ubuntu24.04安装gpfs客户端拷贝软件包在客户端执行命令&#xff0c;提取产品包进入安装包目录&#xff0c;安装相关产品包编译。编译过程中会检查系统依赖接入集群&#xff08;后续&#xff09; Ubuntu24.04安装gpfs客户端 拷贝软件包 scp /root/Spectrum_Scale_Dat…

【UGUI】背包的交互01(道具信息跟随鼠标+道具信息面板显示)

详细程序逻辑过程 初始化物品栏&#xff1a; 在 Awake 方法中&#xff0c;通过标签找到提示框和信息面板。 循环生成10个背包格子&#xff0c;并为每个格子设置图标和名称。 为每个格子添加 UInterMaager232 脚本&#xff0c;以便处理交互事件。 关闭提示框和信息面板&#…

同步互斥相关习题10道 附详解

PV操作 2016 某系统允许最多10个进程同时读文件F&#xff0c;当同时读文件F的进程不满10个时&#xff0c;欲读该文件的其他文件可立即读&#xff0c;当已有10个进程在读文件F时读&#xff0c;其他欲读文件F的进程必须等待&#xff0c;直至有进程读完后退出方可去读 在实现管…

Postman之数据提取

Postman之数据提取 1. 提取请求头\request中的数据2. 提取响应消息\response中的数据3. 通过正在表达式提取4. 提取cookies数据 本文主要讲解利用pm对象对数据进行提取操作&#xff0c;虽然postman工具的页面上也提供了一部分的例子&#xff0c;但是实际使用时不是很全面&#…

(蓝桥杯C/C++)——动态规划(DP)

目录 一、线性DP 1.DP(动态规划)简介 2.动态规划的分析步骤 3.例题讲解 二、二维DP 1.二维DP简介 2.选数异或 三、最长上升子序列LIS 1.LIS简介 2.例题讲解 四、最长公共子序列LCS 1.最长公共子序列 2.最长公共子序列 2.求出具体子序列 一、线性DP 1.DP(动态规划)…

【专题】数据库原理与应用之故障恢复

1. 数据库故障恢复概述 数据库的可恢复性&#xff1a; DBMS能把数据库从被破坏、不正确的状态、恢复到最近一个正确的状态。 恢复管理任务的种类&#xff1a; 一是在未发生故障而系统正常运行时&#xff0c;采取一些必要措施为恢复工作打基础。 二是在发生故障后进行恢复处…