Deconstruct方法必须是void且全为out参数,编译器按变量个数匹配重载,不看类型;私有方法也可用,未赋值out参数会运行时报错。

直接在自定义类里加一个 Deconstruct 方法,就能像元组一样用 var (a, b, c) = obj; 解构——但不是所有写法都生效,关键在签名和调用时机。
Deconstruct 方法必须是 void 且带 out 参数
编译器只认特定签名:返回类型必须是 void,所有参数必须是 out,且顺序对应解构时的变量顺序。哪怕多一个 ref 或少一个 out,解构就静默失败(不报错,但变量未赋值)。
-
public void Deconstruct(out string name, out int age)✅ 正确 -
public (string, int) Deconstruct()❌ 不识别,不是解构方法 -
public void Deconstruct(string name, out int age)❌ 混入非out参数,编译器忽略该重载 -
public void Deconstruct(out string name, out int age, out DateTime? birth)✅ 可重载,支持多版本
解构时类型推导依赖实际声明的变量个数
C# 会根据你写在括号里的变量数量,自动匹配参数个数最接近的 Deconstruct 重载。它不看类型,只数参数个数。
例如有这两个方法:
public void Deconstruct(out string name, out int age) => (name, age) = (Name, Age); public void Deconstruct(out string name, out int age, out string city) => (name, age, city) = (Name, Age, City);
那么:
-
var (n, a) = person;→ 调用两参数版本 -
var (n, a, c) = person;→ 调用三参数版本 -
var (n, _) = person;→ 仍调用两参数版本(_是弃元,不改变参数计数)
字段/属性访问权限不影响 Deconstruct 生效
Deconstruct 方法本身可以是 private、internal 或 public,只要它在当前作用域可见(比如同项目、同程序集),解构就能工作。不需要把字段设为 public,也不需要暴露属性——全靠你在 Deconstruct 里怎么赋值。
常见误操作:
- 把
Name字段设为private,但Deconstruct里写name = this.Name;→ 完全合法 ✅ - 忘了在
Deconstruct里给某个out参数赋值 → 运行时报Use of unassigned out parameter❌ - 在
Deconstruct里读了 null 引用属性却没判空 → 解构时直接抛NullReferenceException
嵌套解构和 foreach 中的陷阱
自定义类支持嵌套解构,但仅限于你显式实现了对应参数个数的 Deconstruct。比如:
var people = new List<Person> { new Person("Alice", 30), new Person("Bob", 25) };
foreach (var (name, age) in people) { ... } // ✅ 有效,前提是 Person 有两参数 Deconstruct
但注意:
- 如果
Person只有三参数Deconstruct,而你写foreach (var (n, a) in people)→ 编译失败 ❌ - 不能对
Deconstruct返回的子对象再解构,除非那个子对象自己也实现了Deconstruct;C# 不递归查找 - 在 LINQ 查询中(如
.Select(x => (x.Name, x.Age)))无法触发自定义类的Deconstruct,它只在赋值语句左侧括号中起作用
最易被忽略的一点:解构不是“反射式读取”,而是硬编码调用——你删掉 Deconstruct,所有解构语句立刻编译失败,不会退化成读属性或字段。所以它很轻量,但也意味着你得主动维护这个方法和使用场景的同步。


















