如何在数据结构中隐式设置父子成员引用
解决方案:自动初始化DataStructure层级的父子引用
核心思路
利用初始化阶段的一次性反射遍历整个层级结构,自动设置Parent引用,并将子类别、属性分别填充到对应列表中。这样既避免了重复编写属性名称的维护问题,又保证了运行时的高效性。
步骤1:优化基础类定义
首先完善Category的构造函数,提前初始化SubCategories和Properties列表,避免空引用问题:
public interface IDataStructureMember { public ICategory Parent { get; set; } } public interface ICategory : IDataStructureMember { public List<ICategory> SubCategories { get; set; } public List<IDataProperty> Properties { get; set; } } public interface IDataProperty : IDataStructureMember { } public abstract class Category : ICategory { public ICategory Parent { get; set; } public List<ICategory> SubCategories { get; set; } public List<IDataProperty> Properties { get; set; } protected Category() { // 提前初始化列表,避免后续操作NullReferenceException SubCategories = new List<ICategory>(); Properties = new List<IDataProperty>(); } } public class DataProperty<T> : IDataProperty { public ICategory Parent { get; set; } public T Value { get; set; } }
步骤2:编写反射初始化工具类
创建一个静态工具类,递归遍历所有Category层级,自动设置父子关系并填充列表:
public static class StructureInitializer { // 对外暴露的初始化入口,从根节点开始遍历 public static void Initialize(ICategory root) { TraverseAndBindReferences(root, null); } private static void TraverseAndBindReferences(ICategory current, ICategory parent) { // 设置当前节点的父引用 current.Parent = parent; // 获取当前类的所有公共实例属性 var properties = current.GetType().GetProperties( System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); foreach (var prop in properties) { var value = prop.GetValue(current); if (value == null) continue; // 处理子类别(实现ICategory的属性) if (typeof(ICategory).IsAssignableFrom(prop.PropertyType)) { var subCategory = (ICategory)value; current.SubCategories.Add(subCategory); // 递归处理子类别 TraverseAndBindReferences(subCategory, current); } // 处理DataProperty(实现IDataProperty的属性) else if (typeof(IDataProperty).IsAssignableFrom(prop.PropertyType)) { var dataProp = (IDataProperty)value; dataProp.Parent = current; current.Properties.Add(dataProp); } // 处理ICategory类型的列表(比如示例中的List<Force>) else if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) { var elementType = prop.PropertyType.GetGenericArguments()[0]; if (typeof(ICategory).IsAssignableFrom(elementType)) { var list = (IEnumerable)value; foreach (var item in list) { var subCategory = (ICategory)item; current.SubCategories.Add(subCategory); TraverseAndBindReferences(subCategory, current); } } } } } }
步骤3:修改DataStructure触发初始化
在根类DataStructure的构造函数中调用初始化工具,完成整个层级的绑定:
public class DataStructure : Category { public EnvironmentData Environment { get; init; } = new(); public ModelData Model { get; init; } = new(); public DataStructure() { // 初始化时自动绑定所有父子引用 StructureInitializer.Initialize(this); } // 内部类保持原定义不变 public class EnvironmentData : Category { public LightData Light { get; init; } = new(); public List<Force> Forces { get; init; } = new(); public class LightData : Category { public LightPositionData LightPosition { get; init; } = new(); public DataProperty<double> Intensity { get; init; } = new(); public class LightPositionData : Category { public DataProperty<List<double>> OriginCoordsXYZ { get; init; } = new(); public DataProperty<List<double>> TargetCoordsXYZ { get; init; } = new(); } } public class Force : Category { public DataProperty<string> ForceName { get; init; } = new(); public DataProperty<double> Magnitude { get; init; } = new(); } } public class ModelData : Category { public DataProperty<string> ModelName { get; init; } = new(); public DataProperty<string> ModelFilePath { get; init; } = new(); public class ModelProperties : Category { public DataProperty<List<double>> BoundingBox { get; init; } = new(); } } }
验证效果
初始化后即可实现你需要的功能:
DataStructure newStructure = new(); // 获取LightData的所有属性 List<IDataProperty> envProperties = newStructure.Environment.Light.Properties; // 获取ModelName的父类别 ICategory p = newStructure.Model.ModelName.Parent; // 验证结果 Console.WriteLine(p == newStructure.Model); // 输出True Console.WriteLine(envProperties.Contains(newStructure.Environment.Light.Intensity)); // 输出True
动态添加子项的处理
如果后续需要动态添加子类别(比如向Forces列表添加新元素),可以给Category添加一个辅助方法,手动绑定父子关系:
public class Category : ICategory { // ... 原有代码 public void AddSubCategory(ICategory subCategory) { subCategory.Parent = this; SubCategories.Add(subCategory); } } // 使用示例 newStructure.Environment.Forces.Add(new DataStructure.EnvironmentData.Force()); newStructure.Environment.AddSubCategory(newStructure.Environment.Forces.Last());
内容的提问来源于stack exchange,提问作者aluc_2513
相关产品推荐
相关产品推荐

