当前位置: 首页 > news >正文

C# 模式匹配(Pattern Matching)

官方文档:

  • 模式匹配概述 - C# | Microsoft Learn、
  • 使用模式匹配避免后跟强制转换的"is"检查
  • 模式匹配完整参考
  • 模式匹配实践教程

标签:record、Deconstruct

PS:Deconstruct可查看我的另一篇👉C# Deconstruct | 简化元组与对象的数据提取-CSDN博客

目录

    • 1. 概述
        • 1.1 支持以下功能
      • 1.2 应用场景
      • 1.3 优点
    • 2. 传统方式 vs 模式匹配
        • 2.1 传统方式(C# 6.0 及之前)
        • 2.2 模式匹配方式(C# 7.0+)
    • 3. C# 中的模式匹配类型
        • 3.1 类型模式(Type Pattern)
        • 3.2 声明模式(Declaration Pattern)
        • 3.3 var 模式
        • 3.4 常量模式 (Constant Pattern)
        • 3.5 关系模式(Relational Pattern)
        • 3.5 逻辑模式(Logical Pattern)
        • 3.6 属性模式(Property Pattern)
        • 3.7 位置模式(Positional Pattern)- 与 record 配合使用
        • 3.8 列表模式 **(List Pattern)**(C# 11+)
    • 3. 实际应用示例
    • 4. 优势
    • 5. 最佳实践
    • 6. 总结

1. 概述

模式匹配是现代编程语言中的一种强大表达力丰富的条件分支方式,它允许检查值的特征(如类型、属性、值等)来简化条件逻辑,并根据检查结果执行相应的代码。

随着版本更新,C# 的模式匹配能力不断增强。

1.1 支持以下功能
  1. 解构提取 – 从复杂结构(如对象、元组等)中提取出内部元素
  2. 类型检查 – 判断值的类型是否符合预期
  3. 条件逻辑 – 将条件判断与变量绑定结合,增强代码表达力
  4. 声明式条件处理 – 以更清晰、结构化的方式编写多分支条件逻辑

1.2 应用场景

  • is表达式:直接条件判断。
  • switch表达式:返回值的模式匹配。
  • switch语句:多分支条件判断。

1.3 优点

模式匹配提高了代码的:

  • 可读性:更简洁地表达复杂条件
  • 安全性:编译器验证完整性,减少遗漏情况
  • 表达力:支持丰富的模式组合和嵌套

2. 传统方式 vs 模式匹配

2.1 传统方式(C# 6.0 及之前)
// 需要多次类型检查和转换
if (shape is Circle)
{Circle circle = (Circle)shape;if (circle.Radius > 5){Console.WriteLine($"Large circle: {circle.Radius}");}
}
else if (shape is Rectangle)
{Rectangle rect = (Rectangle)shape;Console.WriteLine($"Rectangle: {rect.Width}x{rect.Height}");
}
2.2 模式匹配方式(C# 7.0+)
// 单一行内完成类型检查、条件判断和转换
if (shape is Circle { Radius: > 5 } circle)
{Console.WriteLine($"Large circle: {circle.Radius}");
}
else if (shape is Rectangle rect)
{Console.WriteLine($"Rectangle: {rect.Width}x{rect.Height}");
}

3. C# 中的模式匹配类型

3.1 类型模式(Type Pattern)

主要用于检查表达式的运行时类型,通常与 switch 表达式配合使用来实现基于类型的分支处理。

  1. 检查表达式是否匹配指定类型(不声明变量)。

    if (obj is string)
    {  Console.WriteLine("这是一个字符串");
    }
    
  2. switch 表达式配合使用

    var area = shape switch
    {Circle c => Math.PI * c.Radius * c.Radius,Rectangle r => r.Width * r.Height,_ => 0 // 处理 null 和其他值,也叫做弃元模式
    };
    
3.2 声明模式(Declaration Pattern)

同时进行类型检查变量声明

如果表达式能与指定类型匹配,则条件为真,同时会创建一个新的类型化变量(此例中的 circle)来访问该实例的成员,从而避免了显式类型转换。

if (shape is Circle circle)
{Console.WriteLine($"Circle with radius {circle.Radius}");
}
3.3 var 模式

匹配任何表达式(包括 null)并将结果分配给变量。

static bool IsAcceptable(int id, int absLimit) =>SimulateDataFetch(id) is var results && results.Min() >= -absLimit && results.Max() <= absLimit;// 在 when 子句中使用
static Point Transform(Point point) => point switch
{var (x, y) when x < y => new Point(-x, y),var (x, y) when x > y => new Point(x, -y),var (x, y) => new Point(x, y),
};
3.4 常量模式 (Constant Pattern)

检查表达式是否等于指定常量(包括 null、枚举、字面量等)。

if (value is null) return;
if (value is 42) Console.WriteLine("答案是42");
if (value is "hello") Console.WriteLine("打招呼");

枚举值匹配

public State PerformOperation(Operation command) =>command switch{Operation.SystemTest => RunDiagnostics(),Operation.Start => StartSystem(),Operation.Stop => StopSystem(),Operation.Reset => ResetToReady(),_ => throw new ArgumentException("Invalid enum value for command", nameof(command)),};

字符串值匹配

public State PerformOperation(string command) =>command switch{"SystemTest" => RunDiagnostics(),"Start" => StartSystem(),"Stop" => StopSystem(),"Reset" => ResetToReady(),_ => throw new ArgumentException("Invalid string value for command", nameof(command)),};
3.5 关系模式(Relational Pattern)

此模式允许在模式匹配中使用关系运算符(<, >, <=, >=)来将属性值与常量进行比较。它使得基于数值范围的匹配变得非常直观和清晰,完美替代了多个 if-else if 语句链。

// 使用关系运算符进行比较
string sizeCategory = shape switch
{Circle { Radius: >= 10 } => "Extra large",Circle { Radius: >= 5 } => "Large",Circle { Radius: >= 1 } => "Medium",Circle { Radius: > 0 } => "Small",_ => "Invalid"
};
3.5 逻辑模式(Logical Pattern)

逻辑模式允许您使用逻辑运算符 andornot 将多个模式组合起来,形成一个更复杂的复合条件。

模式组合器优先级(从高到低):not > and > or

// 使用逻辑运算符组合条件
string category = shape switch
{Circle { Radius: > 0 and <= 5 } => "Small to medium circle",Rectangle { Width: > 0, Height: > 0 } and not { Width: var w, Height: var h } when w == h => "Non-square rectangle",Rectangle { Width: var w, Height: var h } when w == h => "Square",_ => "Other"
};//Null 检查
string? message = ReadMessageOrDefault();if (message is not null)
{Console.WriteLine(message);
}int? maybe = 12;if (maybe is int number)
{Console.WriteLine($"The nullable int 'maybe' has the value {number}");
}
else
{Console.WriteLine("The nullable int 'maybe' doesn't hold a value");
}
3.6 属性模式(Property Pattern)

属性模式允许直接对对象的属性值进行匹配,而无需先检查类型再访问属性,支持递归匹配。

if (person is { Address.City: "Beijing" }) 
{Console.WriteLine("北京人");
}
static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };// 结合类型检查和变量声明
static string TakeFive(object input) => input switch
{string { Length: >= 5 } s => s[..5],string s => s,ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),ICollection<char> symbols => new string(symbols.ToArray()),null => throw new ArgumentNullException(nameof(input)),_ => throw new ArgumentException("Not supported input type."),
};// 扩展属性模式(C# 10+)
static bool IsInDomain(WeightedPoint point) => point is { X: >= 0, Y: >= 0, Weight: >= 0.0 };
3.7 位置模式(Positional Pattern)- 与 record 配合使用

此模式用于对实现了 Deconstruct 方法的类型(如元组(Tuple)、记录(record)类型)进行解构,并根据其解构后的元素值进行匹配。

_ 代表丢弃符,表示忽略该位置的值。它是处理元组和记录等复合数据的强大工具。

public readonly struct Point
{public int X { get; }public int Y { get; }public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);
}static string Classify(Point point) => point switch
{(0, 0) => "Origin",(1, 0) => "positive X basis end",(0, 1) => "positive Y basis end",_ => "Just a point",
};// 元组模式匹配
static decimal GetGroupTicketPriceDiscount(int groupSize, DateTime visitDate) => (groupSize, visitDate.DayOfWeek) switch
{(<= 0, _) => throw new ArgumentException("Group size must be positive."),(_, DayOfWeek.Saturday or DayOfWeek.Sunday) => 0.0m,(>= 5 and < 10, DayOfWeek.Monday) => 20.0m,(>= 10, DayOfWeek.Monday) => 30.0m,(>= 5 and < 10, _) => 12.0m,(>= 10, _) => 15.0m,_ => 0.0m,
};
3.8 列表模式 (List Pattern)(C# 11+)

处理不规则数据结构,匹配数组或列表中的元素序列,支持切片模式 ..

int[] numbers = { 1, 2, 3 };// 基本匹配
Console.WriteLine(numbers is [1, 2, 3]); // True// 结合关系模式和弃元模式
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]); // True// 使用切片模式
Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]); // True
Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]); // True// 捕获切片结果
void MatchMessage(string message)
{var result = message is ['a' or 'A', .. var s, 'a' or 'A']? $"Message {message} matches; inner part is {s}.": $"Message {message} doesn't match.";Console.WriteLine(result);
}
MatchMessage("aBBA"); // output: Message aBBA matches; inner part is BB.
decimal balance = 0m;
foreach (string[] transaction in ReadRecords())
{balance += transaction switch{[_, "DEPOSIT", _, var amount]     => decimal.Parse(amount),[_, "WITHDRAWAL", .., var amount] => -decimal.Parse(amount),[_, "INTEREST", var amount]       => decimal.Parse(amount),[_, "FEE", var fee]               => -decimal.Parse(fee),_ => throw new InvalidOperationException($"Record {string.Join(", ", transaction)} is not in the expected format!"),};Console.WriteLine($"Record: {string.Join(", ", transaction)}, New balance: {balance:C}");
}

3. 实际应用示例

public record Order(string Id, decimal Amount, string Status, DateTime OrderDate);public decimal CalculateDiscount(Order order) => order switch
{// 高金额且是新客户 - 大折扣{ Amount: > 1000, Status: "New" } => 0.15m,// 节假日订单 - 中等折扣{ OrderDate: { Month: 12, Day: >= 20 and <= 31 } } => 0.10m,// 普通订单 - 小折扣{ Amount: > 500 } => 0.05m,// 默认无折扣_ => 0m
};// 使用示例
var order = new Order("123", 1200m, "New", new DateTime(2023, 12, 25));
decimal discount = CalculateDiscount(order); // 返回 0.15 (15% 折扣)

4. 优势

  1. 更简洁的代码:减少样板代码
  2. 更安全:编译器可以帮助检查穷尽性
  3. 更表达力强:清晰表达复杂的条件逻辑
  4. 更好的可读性:意图更加明确
  5. 与 record 类型完美配合:充分利用 record 的解构功能

5. 最佳实践

  1. 使用括号明确优先级:当组合复杂模式时,使用括号提高可读性和确保正确优先级
  2. 穷尽性检查:确保 switch 表达式处理所有可能情况,避免运行时异常
  3. 性能考量:模式匹配通常比传统 if-else 链更高效,编译器会优化模式匹配逻辑
  4. 可读性:对于复杂匹配逻辑,考虑将模式分解为多个简单模式或使用辅助方法

6. 总结

模式匹配通过将类型检查、属性检查和条件逻辑结合在一起,它提供了比传统 if-elseswitch 语句更强大、更简洁的表达能力。

建议根据需求选择合适的模式,并注意兼容的 C# 版本(如列表模式需 C# 11+)。

http://www.dtcms.com/a/355244.html

相关文章:

  • ASP4644四通道集成方案在射频通信系统中的可行性分析
  • Cesium入门教程(一):Cesium简介
  • PDFMathTranslate:让科学PDF翻译不再难——技术原理与实践指南
  • 回调函数的理解和例子
  • 从用户视角出发:如何提升B端产品的操作效率?
  • 把 AI 塞进「智能水杯」——基于声学指纹的零样本水质检测杯
  • [p2p-Magnet] 队列与处理器 | DHT路由表
  • Chrome 插件开发实战:从入门到精通
  • 基于复旦微ZYNQ7015+VU3P 的双FMC 基带信号处理平台(国产率100%)
  • 基于复旦微RFVU3P FPGA 的基带信号处理板(100%国产率)
  • 水果目标检测[3]:计算机视觉中的深度学习用于监测苹果树生长和水果生产的综合综述
  • 配置 Gitlab 和 Elasticsearch/Zoekt 并使用 Docker Metadata 数据库、Camo 代理服务
  • 鸿蒙Harmony-从零开始构建类似于安卓GreenDao的ORM数据库(五)
  • QP原理讲解
  • 企业微信配置LangBot通信机器人
  • Javascript》》JS》》ES6》》总结
  • 企业招聘难题破解:主流AI面试工具实测对比
  • 【Linux知识】Linux 设置账号密码永不过期
  • Day15 (前端:JavaScript基础阶段)
  • 健永科技RFID技术在羊智能分群管理系统的使用案例
  • leetcode 3446. 按对角线进行矩阵排序 中等
  • 3446. 按对角线进行矩阵排序
  • 前端异常监控,性能监控,埋点,怎么做的
  • 响应式编程框架Reactor【1】
  • React 类生命周期 和 React Hooks 比对
  • 算力沸腾时代,如何保持“冷静”?国鑫液冷SY4108G-G4解锁AI服务器的“绿色空调”!
  • 第五章:Go运行时、内存管理与性能优化之性能分析与pprof工具
  • 配置windows下apache+PHP环境
  • 前端技术之---复制文本
  • docker安装kafka、zookeeper详细步骤