惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Blog of Author Tim Ferriss
P
Privacy & Cybersecurity Law Blog
P
Proofpoint News Feed
S
Schneier on Security
G
GRAHAM CLULEY
The Hacker News
The Hacker News
C
Cybersecurity and Infrastructure Security Agency CISA
Know Your Adversary
Know Your Adversary
C
Cyber Attacks, Cyber Crime and Cyber Security
爱范儿
爱范儿
M
MIT News - Artificial intelligence
V
Vulnerabilities – Threatpost
F
Fortinet All Blogs
月光博客
月光博客
Simon Willison's Weblog
Simon Willison's Weblog
罗磊的独立博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hugging Face - Blog
Hugging Face - Blog
Spread Privacy
Spread Privacy
P
Proofpoint News Feed
A
About on SuperTechFans
云风的 BLOG
云风的 BLOG
Y
Y Combinator Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Tor Project blog
T
Troy Hunt's Blog
Latest news
Latest news
N
Netflix TechBlog - Medium
Vercel News
Vercel News
Stack Overflow Blog
Stack Overflow Blog
Project Zero
Project Zero
N
News and Events Feed by Topic
F
Full Disclosure
酷 壳 – CoolShell
酷 壳 – CoolShell
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CERT Recently Published Vulnerability Notes
H
Hacker News: Front Page
C
Cisco Blogs
I
Intezer
P
Privacy International News Feed
MongoDB | Blog
MongoDB | Blog
L
LINUX DO - 热门话题
Blog — PlanetScale
Blog — PlanetScale
Security Latest
Security Latest
Last Week in AI
Last Week in AI
Scott Helme
Scott Helme
B
Blog
博客园_首页
MyScale Blog
MyScale Blog
Cloudbric
Cloudbric

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
Roslyn语法的模式匹配之EasySyntax增加模式匹配支持
xiangji · 2026-06-22 · via 博客园_首页

一、先看一个模式匹配的Case

  • 该Case是一个使用模式匹配检测回文算法,只有一行代码
  • 这是不是你见过最简洁的检测回文代码
  • 但是这里面用到了不少模式匹配
  • 有逻辑模式、列表模式、var模式和切片模式
  • 模式匹配不仅仅是语法糖,在.net中有很高的地位
  • 所以SourceGenerator非常有必要支持生成模式匹配的代码
  • 为此开源项目EasySyntax全面增加模式匹配的支持
public static bool IsPalindrome(ReadOnlySpan<char> input)
    => input is not [var first, ..var middle, var last] || (first == last && IsPalindrome(middle));

二、 模式匹配的主要类型

1. 类型模式

  • 检查表达式的运行时类型

2. 声明模式

  • 检查表达式的运行时类型,如果匹配成功,请将表达式结果分配给声明的变量

3. 常量模式

  • 测试表达式结果是否等于指定的常量

4. 关系模式

  • 将表达式结果与指定的常量进行比较

5. var模式

  • 匹配任何表达式并将其结果分配给声明的变量

6. 丢弃模式

  • 匹配任何表达式

7. 逻辑模式

  • 测试表达式是否与模式的逻辑组合匹配
  • 通过not、or、and及括号进行组合

8. 带括号模式

  • 可在任何模式两边加上括号
  • 用来强调或更改 逻辑模式中的优先级

9. 列表模式

  • 测试元素序列是否与相应的嵌套模式匹配
  • 用于数组和集合类型

10. 切片模式

  • 切片模式只能显示在列表模式中,不能单独使用
  • 切片模匹配一个子列表
  • 切片模式中可以嵌套子模式

11. 属性模式

  • 测试表达式的属性或字段是否与嵌套模式匹配

12. 位置模式

  • 解构表达式结果并测试结果是否与嵌套模式匹配
  • 用于元组、record类型或其他定义了Deconstruct的类型

其中逻辑模式、列表模式、属性模式和位置模式是可嵌套其他模式的复杂模式

三、 在 C# 中以下场景支持模式匹配:

  • is 表达式
  • switch 语句
  • switch 表达式

四、简单的模式匹配

1. 类型模式

1.1 类型模式的Case

if(fruit is Apple)
	return "I like Apple!";

1.2 EasySyntax语法实现

  • 使用IsType扩展方法
var fruit = SyntaxFactory.IdentifierName("fruit");
var appleType = SyntaxFactory.IdentifierName("Apple");
var statement = fruit.IsType(appleType)
    .If()
        .Add(SyntaxGenerator.Literal("I like Apple!").Return())
    .Build();

1.3 Roslyn原始语法

var fruit = SyntaxFactory.IdentifierName("fruit");
var appleType = SyntaxFactory.IdentifierName("Apple");
var statement = SyntaxFactory.IfStatement(
    SyntaxFactory.IsPatternExpression(fruit, 
        SyntaxFactory.TypePattern(appleType)), 
    SyntaxFactory.ReturnStatement(SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, 
        SyntaxFactory.Literal("I like Apple!"))));

1.4 参看官方阅读

2. 声明模式

2.1 声明模式的Case

if (fruit is Apple apple)
    MakeApplePie(apple);

2.2 EasySyntax 语法实现

  • 使用VariablePattern扩展方法
var fruit = SyntaxFactory.IdentifierName("fruit");
var appleType = SyntaxFactory.IdentifierName("Apple");
var apple = SyntaxFactory.IdentifierName("apple");
var makeApplePieMethod = SyntaxFactory.IdentifierName("MakeApplePie");
var statement = fruit.Is(appleType.VariablePattern(apple.Identifier))
    .If()
        .AddPatter(makeApplePieMethod.Invocation([apple]))
    .Build();

2.3 Roslyn原始语法

var fruit = SyntaxFactory.IdentifierName("fruit");
var appleType = SyntaxFactory.IdentifierName("Apple");
var apple = SyntaxFactory.IdentifierName("apple");
var makeApplePieMethod = SyntaxFactory.IdentifierName("MakeApplePie");
var statement = SyntaxFactory.IfStatement(
    SyntaxFactory.IsPatternExpression(fruit, 
        SyntaxFactory.DeclarationPattern(appleType, SyntaxFactory.SingleVariableDesignation(apple.Identifier))),
    SyntaxFactory.ExpressionStatement(
        SyntaxFactory.InvocationExpression(makeApplePieMethod, 
            SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(apple))))));

2.4 参看官方阅读

3. 常量模式

3.1 声明模式的Case

obj is null

3.2 EasySyntax 语法实现

  • 使用ToPattern扩展方法把表达式转化为常量模式
var obj = SyntaxFactory.IdentifierName("obj");
var expression = obj.Is(SyntaxGenerator.NullLiteral.ToPattern();

3.3 Roslyn原始语法

var obj = SyntaxFactory.IdentifierName("obj");
var expression = SyntaxFactory.IsPatternExpression(obj, 
    SyntaxFactory.ConstantPattern(
        SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)));

3.4 参看官方阅读

4. 关系模式

4.1 声明模式的Case

!= 3

4.2 EasySyntax 语法实现

  • GreaterThanPattern扩展方法
  • GreaterOrEqualPattern扩展方法
  • LessThanPattern扩展方法
  • LessOrEqualPattern扩展方法
  • EqualPattern扩展方法
  • NotEqualPattern扩展方法
 var pattern = SyntaxGenerator.NotEqualPattern(3);

4.3 Roslyn原始语法

var pattern = SyntaxFactory.RelationalPattern(
    SyntaxFactory.Token(SyntaxKind.ExclamationEqualsToken), 
    SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, 
        SyntaxFactory.Literal(3)));

4.4 参看官方阅读

5. var模式

5.1 var模式的Case

GetScores(id) is var scores && scores.Average() >= 60

5.2 EasySyntax 语法实现

  • GreaterThanPattern扩展方法
  • GreaterOrEqualPattern扩展方法
  • LessThanPattern扩展方法
  • LessOrEqualPattern扩展方法
  • EqualPattern扩展方法
  • NotEqualPattern扩展方法
var getScoresMethod = SyntaxFactory.IdentifierName("GetScores");
var scores = SyntaxFactory.IdentifierName("scores");
var id = SyntaxFactory.IdentifierName("id");
var expression = getScoresMethod.Invocation([id])
    .Is(SyntaxGenerator.VarPattern(scores.Identifier))
    .LogicalAnd(scores.Access("Average").Invocation().GreaterOrEqual(SyntaxGenerator.Literal(60)));

5.3 Roslyn原始语法

var getScoresMethod = SyntaxFactory.IdentifierName("GetScores");
var scores = SyntaxFactory.IdentifierName("scores");
var id = SyntaxFactory.IdentifierName("id");
var expression0 = SyntaxFactory.BinaryExpression(SyntaxKind.LogicalAndExpression, 
    SyntaxFactory.IsPatternExpression(
        SyntaxFactory.InvocationExpression(getScoresMethod, SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(
            SyntaxFactory.Argument(id)))), 
        SyntaxFactory.VarPattern(SyntaxFactory.SingleVariableDesignation(scores.Identifier))),
    SyntaxFactory.BinaryExpression(SyntaxKind.GreaterThanOrEqualExpression,
        SyntaxFactory.InvocationExpression(
            SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, 
                scores, 
                SyntaxFactory.IdentifierName("Average"))), 
        SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, 
            SyntaxFactory.Literal(60))));

5.4 参看官方阅读

6. 丢弃模式

  • 丢弃模式常用于switch表达式
  • 也可用于列表和位置模式

6.1 声明模式的Case

date.Day switch
{
    15 => "今夜是月圆之夜",
    _ => "月圆要等到十五"
}

6.2 Roslyn原始语法

  • 使用SyntaxFactory.DiscardPattern()声明丢弃模式
  • 以下case结合了EasySyntax的SwitchExpression语法
var date = SyntaxFactory.IdentifierName("date");
var expression = date.Access("Day")
    .SwitchExpression()
        .Case(SyntaxGenerator.Literal(15), SyntaxGenerator.Literal("今夜是月圆之夜"))
        .Case(SyntaxFactory.DiscardPattern(), SyntaxGenerator.Literal("月圆要等到十五"))
    .Switch.Build();

6.3 EasySyntax语法可以进一步简化

  • SwitchExpression中的Default封装了SyntaxFactory.DiscardPattern()
  • Default是最后一个分支,可以安全的直接Build
var date = SyntaxFactory.IdentifierName("date");
var expression = date.Access("Day")
    .SwitchExpression()
        .Case(SyntaxGenerator.Literal(15), SyntaxGenerator.Literal("今夜是月圆之夜"))
        .Default(SyntaxGenerator.Literal("月圆要等到十五"))
    .Build();

6.4 参看官方阅读

五、逻辑模式

  • 逻辑模式嵌套了其他模式
  • 逻辑模式通过and、or和not及括号组装其他模式

1. 逻辑模式的Case

  • 该Case通过and组装了两个关系模式
0 and < 10

2. EasySyntax 语法实现

  • And扩展方法
  • Or扩展方法
  • Not扩展方法
var pattern = SyntaxGenerator.GreaterThanPattern(0)
    .And(SyntaxGenerator.LessThanPattern(10));

3. Roslyn原始语法

var pattern = SyntaxFactory.BinaryPattern(SyntaxKind.AndPattern,
    SyntaxFactory.RelationalPattern(SyntaxFactory.Token(SyntaxKind.GreaterThanToken),
        SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression,
            SyntaxFactory.Literal(0))),
    SyntaxFactory.Token(SyntaxKind.AndKeyword),
    SyntaxFactory.RelationalPattern(SyntaxFactory.Token(SyntaxKind.LessThanToken),
        SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression,
            SyntaxFactory.Literal(10))));

4. 参看官方阅读

六、带括号模式

  • 可在任何模式两边加上括号
  • 用来强调或更改逻辑模式中的优先级

1 逻辑模式的Case

  • 该Case通过and组装了两个关系模式
input is not (float or double)

2 EasySyntax 语法实现

  • 使用Parenthesized扩展方法转化为带括号模式
var input = SyntaxFactory.IdentifierName("input");
var pattern = SyntaxFactory.TypePattern(SyntaxGenerator.FloatType)
    .Or(SyntaxFactory.TypePattern(SyntaxGenerator.DoubleType))
    .Parenthesized()
    .Not();
var expression = input.Is(pattern);

3 Roslyn原始语法

var input = SyntaxFactory.IdentifierName("input");
var pattern = SyntaxFactory.UnaryPattern(
    SyntaxFactory.ParenthesizedPattern(
        SyntaxFactory.BinaryPattern(
            SyntaxKind.OrPattern, 
            SyntaxFactory.TypePattern(
                SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.FloatKeyword))), 
            SyntaxFactory.Token(SyntaxKind.OrKeyword), 
            SyntaxFactory.TypePattern(
                SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DoubleKeyword))))));
var expression = SyntaxFactory.IsPatternExpression(input, pattern);

4. 参看官方阅读

七、列表模式

  • 测试元素序列是否与相应的嵌套模式匹配
  • 用于字符串、数组和集合类型

1.列表模式的Case

  • 该Case由3个模式组成
  • 前两个是常量模式
  • 第三个是丢弃模式
name is ['曾', '国', _ ]

2.EasySyntax语法实现

  • 使用ListPatternBuilder组装多个模式
var name = SyntaxFactory.IdentifierName("name");
var pattern = new ListPatternBuilder()
    .Add(SyntaxGenerator.Literal('曾'))
    .Add(SyntaxGenerator.Literal('国'))
    .Add(SyntaxFactory.DiscardPattern())
    .Build();
var expression = name.Is(pattern);

3.Roslyn原始语法

var name = SyntaxFactory.IdentifierName("name");
var pattern = SyntaxFactory.ListPattern(SyntaxFactory.SeparatedList<PatternSyntax>([
    SyntaxFactory.ConstantPattern(SyntaxFactory.LiteralExpression(SyntaxKind.CharacterLiteralExpression, 
        SyntaxFactory.Literal('曾'))),
    SyntaxFactory.ConstantPattern(SyntaxFactory.LiteralExpression(SyntaxKind.CharacterLiteralExpression, 
        SyntaxFactory.Literal('国'))),
    SyntaxFactory.DiscardPattern()]));
var expression = name.Is(pattern);

4. 参看官方阅读

八、切片模式

  • 切片模式只能显示在列表模式中,不能单独使用
  • 切片模匹配一个子列表
  • 切片模式中可以嵌套子模式

1.切片模式的Case

  • 其中.. var middle就是切片模式
  • 该Case定义了一个使用切片模式和列表模式实现的回文算法
  • 通过模式提取首字母、尾字母和中间切片
  • 如果首尾字母相同再用中间切片递归调用该算法
  • 非常简洁高效
static bool IsPalindrome(ReadOnlySpan<char> input)
    => input is not [var first, .. var middle, var last] || (first == last && IsPalindrome(middle));

2.EasySyntax语法实现

  • 使用Slice扩展方法定义切片模式
  • 用于把原模式转化为切片模式
var input = SyntaxFactory.IdentifierName("input");
var inputType = SyntaxGenerator.Generic("ReadOnlySpan", SyntaxGenerator.CharType);
var isPalindromeMethod = SyntaxFactory.IdentifierName("IsPalindrome");
var first = SyntaxFactory.IdentifierName("first");
var middle = SyntaxFactory.IdentifierName("middle");
var last = SyntaxFactory.IdentifierName("last");
var middleSlice = SyntaxGenerator.VarPattern(middle.Identifier)
    .Slice();
var pattern = new ListPatternBuilder()
    .Add(SyntaxGenerator.VarPattern(first.Identifier))
    .Add(middleSlice)
    .Add(SyntaxGenerator.VarPattern(last.Identifier))
    .Build();
var expression1 = input.Is(pattern.Not());
var expression2 = first.Equal(last).LogicalAnd(isPalindromeMethod.Invocation([middle]));
var body = expression1.LogicalOr(expression2.Parenthesized());
var method = SyntaxGenerator.BoolType.Method(isPalindromeMethod.Identifier, inputType.Parameter(input.Identifier))
    .Static()
    .WithExpressionBody(body);

3.Roslyn原始语法实现切片模式

  • 以下代码等效EasySyntax语法的SyntaxGenerator.VarPattern(middle.Identifier).Slice()
SyntaxFactory.SlicePattern(SyntaxGenerator.VarPattern(middle.Identifier));

4. 参看官方阅读

九、属性模式

  • 由属性名(或字段名)及其模式组成
  • 可以同时定义多个属性(或字段)

1.逻辑模式的Case

  • 该Case包含了两个属性
  • Month使用常量模式
  • Day使用关系模式
{ Month: 10, Day: <= 7 }

2.EasySyntax语法实现

  • 使用PropertyPatternBuilder组装多个属性(或字段)
var nationalDays = new PropertyPatternBuilder(null)
    .Add("Month", SyntaxGenerator.Literal(10))
    .Add("Day", SyntaxGenerator.LessOrEqualPattern(7))
    .Build();

3.Roslyn原始语法

var nationalDays = SyntaxFactory.RecursivePattern(
    null, 
    null, 
    SyntaxFactory.PropertyPatternClause(SyntaxFactory.SeparatedList([
        SyntaxFactory.Subpattern(
            SyntaxFactory.NameColon("Month"), 
            SyntaxFactory.ConstantPattern(SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, 
                SyntaxFactory.Literal(10)))),
        SyntaxFactory.Subpattern(
            SyntaxFactory.NameColon("Day"), 
            SyntaxFactory.RelationalPattern(
                SyntaxFactory.Token(SyntaxKind.LessThanEqualsToken), 
                SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, 
                    SyntaxFactory.Literal(7))))])),
    null);

4. 属性模式可选参数

  • 可以定义一个可选的类型参数,相当于类型模式
  • 还可以定义一个可选的变量名,相当于声明模式

4.1 EasySyntax的Case

  • 该case的类型参数为Food
  • 该case的变量名为food
var thing = SyntaxFactory.IdentifierName("thing");
var food = SyntaxFactory.IdentifierName("food");
var foodType = SyntaxFactory.IdentifierName("Food");
var now = SyntaxGenerator.DateTimeType.Access("Now");
var pattern = new PropertyPatternBuilder(foodType, food.Identifier)
     .Add("ExpirationDate", SyntaxGenerator.GreaterThanPattern(now))
     .Build();
var method = foodType.Nullable().Method("FindFoot", SyntaxGenerator.ObjectType.Parameter(thing.Identifier))
    .ToBuilder()
    .If(thing.Is(pattern))
    .Return(food)
    .Return(SyntaxGenerator.NullLiteral);

4.2 该Case生成以下代码

  • 该Case描述一个查找食物的场景
  • 先确认该东西是否为食物
  • 再确认是否在保质期内
Food? FindFoot(object thing)
{
    if (thing is Food { ExpirationDate: > DateTime.Now } food)
        return food;
    return null;
}

5. 参看官方阅读

十、位置模式

  • 解构表达式结果并测试结果是否与嵌套模式匹配
  • 用于元组、record类型或其他定义了Deconstruct的类型
  • 位置模式功能很强大也比较复杂

1.位置模式的简单Case

point is (0, 0)

2.EasySyntax语法实现

  • 使用PropertyPatternBuilder组装多个属性(或字段)
var point = SyntaxFactory.IdentifierName("point");
var pattern = new PositionalPatternBuilder(null)
    .Add(SyntaxGenerator.Literal(0))
    .Add(SyntaxGenerator.Literal(0))
    .Build();
var isOrigin = point.Is(pattern);

3.Roslyn原始语法

var nationalDays = SyntaxFactory.RecursivePattern(
    null, 
    null, 
    SyntaxFactory.PropertyPatternClause(SyntaxFactory.SeparatedList([
        SyntaxFactory.Subpattern(
            SyntaxFactory.NameColon("Month"), 
            SyntaxFactory.ConstantPattern(SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, 
                SyntaxFactory.Literal(10)))),
        SyntaxFactory.Subpattern(
            SyntaxFactory.NameColon("Day"), 
            SyntaxFactory.RelationalPattern(
                SyntaxFactory.Token(SyntaxKind.LessThanEqualsToken), 
                SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, 
                    SyntaxFactory.Literal(7))))])),
    null);

4. 位置模式可选参数

  • 可以定义一个可选的type(类型参数),相当于类型模式
  • 还可以定义一个可选的name(变量名),相当于声明模式

4.1 EasySyntax的Case

  • 该case的类型参数为Point2D和Point3D
  • 该case的变量名为p
var point2DType = SyntaxFactory.IdentifierName("Point2D");
var point3DType = SyntaxFactory.IdentifierName("Point3D");
var point = SyntaxFactory.IdentifierName("point");
var p = SyntaxFactory.IdentifierName("p");
var pattern1 = new PositionalPatternBuilder(point2DType, p.Identifier)
    .Add(SyntaxGenerator.GreaterThanPattern(0))
    .Add(SyntaxGenerator.GreaterThanPattern(0))
    .Build();
var pattern2 = new PositionalPatternBuilder(point3DType, p.Identifier)
    .Add(SyntaxGenerator.GreaterThanPattern(0))
    .Add(SyntaxGenerator.GreaterThanPattern(0))
    .Add(SyntaxGenerator.GreaterThanPattern(0))
    .Build();
var body = point.SwitchExpression()
    .Case(pattern1, p.Access("ToString").Invocation())
    .Case(pattern2, p.Access("ToString").Invocation())
    .Default(SyntaxGenerator.StringType.Access("Empty"))
    .Build();
var method = SyntaxGenerator.StringType.Method("PrintIfAllCoordinatesArePositive",
        SyntaxGenerator.ObjectType.Parameter(point.Identifier))
            .WithExpressionBody(body);

4.2 该Case生成以下代码

  • 如果是二维的点且每个坐标值都大于0
  • 或者是三维的点且每个坐标值都大于0
  • 否则返回空
string PrintIfAllCoordinatesArePositive(object point) => point switch
{
    Point2D(> 0, > 0) p => p.ToString(),
    Point3D(> 0, > 0, > 0) p => p.ToString(),
    _ => string.Empty
};

5. 位置模式支持属性名

  • 增加属性名能提高代码的可读性

5.1 EasySyntax的Case

  • 使用NamedPositionalPatternBuilder来支持属性名
  • NamedPositionalPatternBuilder也支持type和name可选参数
  • 使用NamedPositionalPatternBuilder也可以轻松重写4.的Case,限与篇幅就不举例了
var point = SyntaxFactory.IdentifierName("point");
var pattern = new NamedPositionalPatternBuilder(null)
    .Add("X", SyntaxGenerator.Literal(0))
    .Add("Y", SyntaxGenerator.Literal(0))
    .Build();
var isOrigin = point.Is(pattern);

5.2 该Case生成以下代码

  • 增加属性名X和Y使得代码可读性明显的提高
point is (X: 0, Y: 0)

6. 位置模式还可以附加属性模式

  • 不是嵌套,是属性模式作为位置模式的可选参数

6.1 例如以下代码

  • WeightedPoint是结构体,另外还有一个属性Weight
public record WeightedPoint(int X, int Y)
{
    public int Weight { get; set; }
}

6.2 EasySyntax的Case

  • 使用RecursivePatternBuilder来定义含属性模式的位置模式
  • RecursivePatternBuilder也支持type和name可选参数
  • NamedRecursivePatternBuilder能实现位置参数属性名表示及属性模式,限与篇幅本文不展开
var point = SyntaxFactory.IdentifierName("point");
var builder = new RecursivePatternBuilder(null);
builder.Positional.Add(SyntaxGenerator.GreaterOrEqualPattern(0))
    .Add(SyntaxGenerator.GreaterOrEqualPattern(0));
builder.Property.Add("Weight", SyntaxGenerator.GreaterThanPattern(0));
var isInDomain = point.Is(builder.Build());

6.3 该Case生成以下代码

point is (>= 0, >= 0) { Weight: > 0 }

7. 参看官方阅读

源码托管地址: https://github.com/donetsoftwork/Hand.Generators ,欢迎大家直接查看源码。
gitee同步更新:https://gitee.com/donetsoftwork/hand.-generators

如果大家喜欢请动动您发财的小手手帮忙点一下Star,谢谢!!!