如何用C#不可变双向链接对象(Records)实现父子双向引用?
C# Records实现双向父子对象链接的便捷方案
在C#中实现父子对象的双向链接(Parent.Child和Child.Parent互指),不需要依赖反射,有几种更直接且类型安全的方案,可根据是否需要保持record的不可变性来选择:
1. 静态工厂方法(保持不可变性)
如果要严格遵循record的不可变设计(使用init属性),可以通过私有构造函数+静态工厂方法封装双向关联逻辑:
public record Parent { public Child? Child { get; init; } public string Name { get; init; } // 私有构造函数,避免外部直接实例化 private Parent(string name, Child? child) { Name = name; Child = child; } // 静态工厂方法,完成双向绑定 public static Parent CreateWithChild(string parentName, string childName) { // 先创建未关联子对象的父实例 var tempParent = new Parent(parentName, null); // 创建子对象并关联父实例 var child = new Child(childName, tempParent); // 利用record的with表达式生成关联后的父实例(init属性仅能在初始化时设置) return tempParent with { Child = child }; } } public record Child { public Parent Parent { get; init; } public string Name { get; init; } public Child(string name, Parent parent) { Name = name; Parent = parent; } } // 使用示例 var parent = Parent.CreateWithChild("ParentA", "ChildA"); // parent.Child.Parent 会指向parent本身
这种方式完全保留record的不可变性,所有属性通过init初始化,关联逻辑被封装在工厂方法中,外部调用无需关心内部细节。
2. 可变属性(最简实现)
如果可以接受部分属性可变(放弃init改用set),可直接在子对象的构造函数中完成双向绑定:
public record Parent { // 使用set允许后续修改 public Child? Child { get; set; } public string Name { get; init; } } public record Child { public Parent Parent { get; init; } public string Name { get; init; } public Child(string name, Parent parent) { Name = name; Parent = parent; // 直接给父对象的Child属性赋值,完成双向关联 parent.Child = this; } } // 使用示例 var parent = new Parent { Name = "ParentB" }; var child = new Child("ChildB", parent); // 此时parent.Child和child.Parent已互指
这是代码量最少的实现,但Parent.Child变为可变属性,若不需要严格的不可变性,这是最便捷的方案。
3. 构建器模式(复杂场景适配)
如果对象有较多属性,或需要创建更复杂的关联结构,可用构建器模式封装关联逻辑:
public class ParentChildBuilder { private string _parentName = string.Empty; private string _childName = string.Empty; public ParentChildBuilder SetParentName(string name) { _parentName = name; return this; } public ParentChildBuilder SetChildName(string name) { _childName = name; return this; } public (Parent LinkedParent, Child LinkedChild) Build() { var tempParent = new Parent(_parentName, null); var child = new Child(_childName, tempParent); var linkedParent = tempParent with { Child = child }; return (linkedParent, child); } } // 对应的不可变record public record Parent(string Name, Child? Child); public record Child(string Name, Parent Parent); // 使用示例 var (parent, child) = new ParentChildBuilder() .SetParentName("ParentC") .SetChildName("ChildC") .Build();
构建器模式把关联逻辑完全封装,外部仅需设置参数并调用Build,适合需要扩展更多关联逻辑的场景。
内容的提问来源于stack exchange,提问作者KHRZ
相关产品推荐
相关产品推荐

