位置模式仅对实现了Deconstruct方法的类型生效,包括元组、record及手动添加Deconstruct的class/struct;不支持普通class或未实现该方法的struct,也不支持List<string>等内置集合类型。

位置模式不是“自动解构任意对象”的魔法,它只对实现了 Deconstruct 方法的类型(如 record、元组、自定义类)生效;直接对普通 class 或没有 Deconstruct 的 struct 使用会编译失败。
位置模式能匹配哪些类型?
它依赖编译器在编译期查找目标类型的 Deconstruct 方法。只有该方法存在且签名匹配,位置模式才可用。
- 元组(
(int, string)、(x: int, y: int))天然支持,无需额外代码 -
record类型自动生成Deconstruct,参数顺序与构造函数一致 - 手动为
class或struct添加void Deconstruct(out T1 p1, out T2 p2)才能启用 -
List<T>、string、Dictionary<K,V>等内置集合类型不支持——别试if (list is [var x, var y]),那是 C# 11 的列表模式,不是位置模式
is 和 switch 中的位置模式写法差异
两者语法一致,但语义约束不同:在 is 表达式中,位置模式仅用于判断+绑定变量;在 switch 表达式中,每个分支必须返回相同类型,且不能漏掉 _ 或完整覆盖(否则编译报错)。
-
is示例:if (point is (var x, var y) when x == y)—— 绑定x和y后加条件判断 -
switch示例:point switch { (0, 0) => "origin", (var x, var y) => $"({x},{y})" }—— 必须穷尽或兜底,否则 CS8509 警告 - 错误写法:
point switch { (var x, _) => x * x }—— 缺少_分支,编译失败(除非类型是可空或已知封闭枚举)
为什么 (var a, var b) 有时不绑定变量?
常见于你误用了类型模式而非位置模式。比如写成 if (obj is (int, string)),这其实是常量模式(匹配值为 (int, string) 这个元组字面量),不是解构;要解构必须用 var 或具体变量名。
- ✅ 正确解构:
if (tup is (var x, var y))、if (rec is Person(var name, var age)) - ❌ 不解构(仅类型/值匹配):
if (tup is (int, string))、if (rec is Person) - ⚠️ 隐患:
if (tup is (0, _))匹配第一个元素为 0 的二元组,但不绑定任何变量——_是丢弃,不是占位符
嵌套位置模式要注意 Deconstruct 的调用顺序
当你写 if (outer is Outer((var x, var y), var z)),编译器会先调用 Outer.Deconstruct,再对第一个输出参数(假设是元组)递归调用其 Deconstruct。如果中间某层没实现 Deconstruct,就直接编译失败,不会运行时抛异常。
- record 嵌套安全:
record A(B b); record B(int x, int y);→if (a is A((var x, var y)))可用 - 普通 class 嵌套失败:
class A { public B Inner; }即使B有Deconstruct,A没有,is A((var x, var y))就不合法 - 性能提示:每次匹配都会触发实际的
Deconstruct调用(非内联),高频路径慎用深层嵌套


















