-
模式匹配——C#编写复杂对象类型判断
第一部分:C#基础入门
模式匹配——复杂对象类型判断
实例介绍
传统的类型判断(如as转换+null检查、typeof比较)在处理复杂对象时,代码繁琐且可读性差。比如判断一个图形是圆形、矩形还是三角形,并计算其面积,传统写法需要多层if-else嵌套,而模式匹配能通过简洁的语法完成类型判断、属性提取和分支处理,大幅提升代码质量。
C# 7+引入的模式匹配特性,从简单的类型匹配逐步扩展到属性模式、位置模式、var模式等,支持复杂场景下的对象解构和条件判断。本节通过“图形面积计算”场景,带你掌握模式匹配的核心用法。
需求分析
设计一个图形面积计算工具,核心需求:
1.支持多图形类型:圆形(Circle)、矩形(Rectangle)、三角形(Triangle)、复合图形(CompositeShape,包含多个子图形);
2.简洁类型判断:避免繁琐的as+null检查;
3.数据提取:自动从对象中提取属性值(如圆形的半径、矩形的宽高);
4.嵌套处理:支持复合图形的递归面积计算;
5.可读性:代码逻辑清晰,易于维护。
代码实现
-
定义图形接口与类
csharp
using System;
using System.Collections.Generic;
// 图形接口
public interface IShape {}
// 圆形:包含半径
public class Circle : IShape {
public double Radius { get; }
public Circle(double radius) => Radius = radius;
// 位置模式支持:解构方法
public void Deconstruct(out double radius) => radius = Radius;
}
// 矩形:包含宽和高
public class Rectangle : IShape {
public double Width { get; }
public double Height { get; }
public Rectangle(double width, double height) => (Width, Height) = (width, height);
public void Deconstruct(out double width, out double height) => (width, height) = (Width, Height);
}
// 三角形:包含底和高
public class Triangle : IShape {
public double Base { get; }
public double Height { get; }
public Triangle(double @base, double height) => (Base, Height) = (@base, height); // @base避免关键字冲突
public void Deconstruct(out double @base, out double height) => (@base, height) = (Base, Height);
}
// 复合图形:包含多个子图形
public class CompositeShape : IShape {
public List<IShape> Shapes { get; }
public CompositeShape(List<IShape> shapes) => Shapes = shapes;
}
-
模式匹配计算面积
csharp
public static class AreaCalculator {
// 计算单个图形面积:使用switch表达式+模式匹配
public static double CalculateArea(IShape shape) => shape switch {
// 类型模式:判断类型并提取变量
Circle circle => Math.PI * circle.Radius * circle.Radius,
// 属性模式:检查属性并提取值
Rectangle { Width: var w, Height: var h } => w * h,
// 位置模式:通过解构方法提取值(依赖Deconstruct)
Triangle(var b, var h) => 0.5 * b * h,
// 复合图形:递归计算子图形面积之和
CompositeShape composite => composite.Shapes.Sum(CalculateArea),
// null模式:处理空值
null => 0,
// 通配符模式:匹配所有未处理的类型
_ => throw new ArgumentException("未知图形类型")
};
// 示例:使用is表达式判断类型并提取数据
public static void PrintShapeInfo(IShape shape) {
if (shape is Circle { Radius: > 5 } largeCircle) {
Console.WriteLine($"大圆形:半径{largeCircle.Radius}");
} else if (shape is Rectangle rect) {
Console.WriteLine($"矩形:宽{rect.Width},高{rect.Height}");
} else if (shape is Triangle tri) {
Console.WriteLine($"三角形:底{tri.Base},高{tri.Height}");
}
}
}
// 测试代码
class Program {
static void Main() {
// 构建图形
var circle = new Circle(3);
var rect = new Rectangle(4, 5);
var triangle = new Triangle(6, 7);
var composite = new CompositeShape(new List<IShape> { circle, rect, triangle });
// 计算面积
Console.WriteLine($"圆形面积:{AreaCalculator.CalculateArea(circle):F2}"); // 28.27
Console.WriteLine($"矩形面积:{AreaCalculator.CalculateArea(rect):F2}"); //20.00
Console.WriteLine($"三角形面积:{AreaCalculator.CalculateArea(triangle):F2}"); //21.00
Console.WriteLine($"复合图形面积:{AreaCalculator.CalculateArea(composite):F2}"); //69.27
// 打印图形信息
AreaCalculator.PrintShapeInfo(new Circle(6)); //大圆形:半径6
AreaCalculator.PrintShapeInfo(rect); //矩形:宽4,高5
}
}
逐行讲解
-
图形类定义
IShape接口:标记所有图形类型,无具体方法;
Circle类:包含Radius属性,实现Deconstruct方法(支持位置模式);
Rectangle类:包含Width和Height属性,Deconstruct方法解构为两个变量;
Triangle类:包含Base和Height属性,注意@base避免与关键字冲突;
CompositeShape类:包含Shapes列表,用于嵌套多个图形。 -
CalculateArea方法(switch表达式)
类型模式:Circle circle判断类型并将shape转换为Circle变量;
属性模式:Rectangle { Width: var w, Height: var h }提取Width和Height为变量w和h;
位置模式:Triangle(var b, var h)通过Deconstruct方法直接提取底和高;
复合图形处理:CompositeShape composite递归计算所有子图形面积之和;
null模式:null处理空输入;
通配符模式:_匹配所有未处理类型,抛出异常。 -
PrintShapeInfo方法(is表达式)
is表达式+属性模式:shape is Circle { Radius: >5 } largeCircle判断是否为半径大于5的圆形,并提取变量;
类型模式:shape is Rectangle rect判断类型并转换变量;
简洁性:避免传统的as转换+null检查(如var circle = shape as Circle; if (circle != null && circle.Radius>5))。
基础知识拓展 -
模式匹配的核心模式类型
| 模式类型 | 说明 | 示例 |
| ---- | ---- | ---- |
| 类型模式 | 判断对象类型并转换为该类型变量 | shape is Circle c |
| 属性模式 | 检查对象属性值并提取 | Circle { Radius: var r } |
| 位置模式 | 通过Deconstruct方法解构对象为位置参数 | Triangle(var b, var h) |
| var模式 |捕获任意值为变量(用于中间计算) | { Width: var w, Height: var h } |
| 常量模式 | 匹配常量值 | shape is 0(匹配null?不,常量模式是具体值) |
| 通配符模式 | 匹配所有未处理的情况 | _ | -
模式匹配的优势
简洁性:减少类型转换和null检查的样板代码;
可读性:分支逻辑清晰,直接表达意图;
安全性:编译时检查分支覆盖(如switch表达式需覆盖所有可能情况);
灵活性:支持嵌套模式(如CompositeShape { Shapes: [var first, ..var rest] })。 -
与传统方法的对比
传统方法计算面积:
csharp
public static double OldCalculateArea(IShape shape) {
if (shape == null) return 0;
if (shape is Circle circle) {
return Math.PI * circle.Radius * circle.Radius;
} else if (shape is Rectangle rect) {
return rect.Width * rect.Height;
} else if (shape is Triangle tri) {
return 0.5 * tri.Base * tri.Height;
} else if (shape is CompositeShape composite) {
double sum =0;
foreach(var s in composite.Shapes) sum += OldCalculateArea(s);
return sum;
} else {
throw new ArgumentException();
}
}
模式匹配版本更简洁,逻辑更清晰,尤其是switch表达式的链式写法。
4. C#版本新特性
C#7:引入is表达式和模式匹配switch;
C#8:引入switch表达式、属性模式、位置模式;
C#9:增强位置模式(支持记录类型自动解构)、扩展属性模式;
C#10:引入逻辑模式(and/or/not),如shape is Circle and { Radius: >5 };
C#11:引入列表模式,如Shapes: [var first, var second]匹配前两个元素。
总结
模式匹配是C#处理复杂类型判断和数据提取的强大工具,核心价值在于简化代码、提升可读性和安全性。在实际开发中,常用于:
处理多类型数据(如API返回的不同响应类型);
解析复杂结构(如JSON数据、配置文件);
递归处理嵌套对象(如复合图形、树形结构)。
掌握模式匹配,能让你写出更优雅、更易维护的代码,告别繁琐的类型转换和null检查。
本站原创,转载请注明出处:










