C#中使用对象初始化器存储层级数据父对象引用可行吗?
关于对象初始化器中引用父对象的问题
首先直接给结论:C# 里没有专门指代外层正在初始化的父对象的关键字,所以你没法在嵌套的对象初始化器里直接写?Scenario?或?Step?这种引用。想要给子对象的parent属性赋值为父对象,必须拆分步骤,先声明父对象,再给子对象赋值。
传统解决方案:先声明父对象再赋值
你需要先创建父对象实例,再逐个添加子对象,此时就能直接引用已声明的父对象了。针对你的代码,修改后的示例如下:
// 1. 先创建Scenario父对象 var newScenario = new Scenario() { scenarioNumber = Scenarios.Count, scenarioDescription = "Example scenario", Steps = new BindingList<Step>() }; // 2. 添加前两个Step,直接引用newScenario作为parent newScenario.Steps.Add(new Step(){ parent = newScenario, stepNumber = 1, subSteps = new BindingList<Step>() }); newScenario.Steps.Add(new Step(){ parent = newScenario, stepNumber = 2, subSteps = new BindingList<Step>() }); // 3. 处理带subSteps的第三个Step:先创建这个Step,再添加它的子Step var thirdStep = new Step(){ parent = newScenario, stepNumber = 3, subSteps = new BindingList<Step>() }; thirdStep.subSteps.Add(new Step() { parent = thirdStep, stepNumber = 1, subSteps = new BindingList<Step>() }); thirdStep.subSteps.Add(new Step() { parent = thirdStep, stepNumber = 2, subSteps = new BindingList<Step>() }); newScenario.Steps.Add(thirdStep); // 4. 最后将Scenario加入集合 Scenarios.Add(newScenario);
这种方式虽然多了几步,但逻辑清晰,是当前C#语法下最直接的实现方式。
更优雅的替代方案:自动关联父对象
如果你不想每次手动设置parent,可以利用BindingList的AddingNew事件,在子对象被添加到集合时自动绑定父对象。这样能让代码回到对象初始化器的简洁风格,同时避免手动赋值的繁琐。
第一步:修改类的构造函数,添加自动关联逻辑
public class Scenario { public int scenarioNumber { get; set; } public string scenarioDescription { get; set; } public BindingList<Step> Steps { get; set; } public Scenario() { Steps = new BindingList<Step>(); // 当向Steps添加新Step时,自动设置parent为当前Scenario Steps.AddingNew += (sender, e) => { if (e.NewObject is Step step) { step.parent = this; } }; } } public class Step { public object parent { get; set; } public int stepNumber { get; set; } public BindingList<Step> subSteps { get; set; } public Step() { subSteps = new BindingList<Step>(); // 当向subSteps添加新Step时,自动设置parent为当前Step subSteps.AddingNew += (sender, e) => { if (e.NewObject is Step subStep) { subStep.parent = this; } }; } }
第二步:简化后的初始化代码
现在你可以像最开始想的那样用嵌套对象初始化器,不用手动设置parent:
Scenarios.Add(new Scenario() { scenarioNumber = Scenarios.Count, scenarioDescription = "Example scenario", Steps = new BindingList<Step>() { new Step(){ stepNumber = 1 }, new Step(){ stepNumber = 2 }, new Step(){ stepNumber = 3, subSteps = new BindingList<Step>() { new Step(){ stepNumber = 1 }, new Step(){ stepNumber = 2 } } } } });
这种方式更符合面向对象的封装思想,把父对象和子对象的关联逻辑封装在类内部,避免外部代码重复设置。
内容的提问来源于stack exchange,提问作者Jay Double
相关产品推荐
相关产品推荐

