如何在LogicStatement实例化时同步上级类的Expression与Value属性
我有如下类结构:
public class LogicStatement : ILogicStatement { public string TestLogic { get; set; } public string CompareLogic { get; set; } public string Operator { get; set; } public string Expression(); public bool Value(); } public class Test : ITest { public int TestId { get; set; } public int LiteralId { get; set; } public string TestName { get; set; } public string TestText { get; set; } public string TestDisplayName { get; } public ILogicStatement LogicStatement { get; set; } public string Expression { get; set; } public bool Value { get; set; } } public class Literal : ILiteral { // 其他属性成员... public List<ITest> Tests {get; set;} // 其他方法成员... }
Test类包含LogicStatement类型成员,Literal类包含List<ITest>类型成员,所有类都有同名的Expression、Value属性及Expression()、Value()方法,这些属性和方法的值都依赖LogicStatement类的内容。
项目里我用接口实例化对象来遵循依赖倒置原则,通过工厂类创建Test和LogicStatement实例:
public static class Factory { public static ILogicStatement CreateLogicStatement() { return new LogicStatement(); } public static ITest CreateTest() { return new Test(CreateLogicStatement()); } public static List<ITest> CreateTests() { return new List<ITest>(); } // 其他类的创建方法类似 }
我的目标是让Expression()和Value()仅在底层LogicStatement类中计算一次,然后把结果同步到上级类的对应属性中。现在通过Dapper获取数据后,所有层级的其他成员值都正确,但Expression、Value属性及对应方法的值都是null。单独测试LogicStatement.Expression()和LogicStatement.Value()能返回预期值,但从Test类开始这些属性就为null。
我的构造函数如下:
public LogicStatement() { Expression(); Value(); } public Test(ILogicStatement logicStatement) { _logicStatement = logicStatement; Expression = _logicStatement.Expression(); Value = _logicStatement.Value(); } public Literal(ITest test) { _test = test; Expression = _test.Expression; Value = _test.Value; }
主代码:
List<ILiteral> literals = Factory.CreateLiterals(); List<ITest> tests = Factory.CreateTests(); List<ILogicStatement> logicStatements = Factory.CreateLogicStatements(); literals = GetDataFromDapper();
我怀疑是对象实例化方式有问题,想知道不用事件的前提下,怎么在LogicStatement实例化时触发Expression()和Value(),并同步上级类的对应属性,始终保证test[i].Expression == literal[i].Expression == LogicStatement[i].Expression()。我是OOP初学者,希望得到基础原理的解释。
基础原理
- 单向依赖与委托:既然所有
Expression和Value的根源都是LogicStatement,上级类(Test、Literal)无需自己存储这些值,直接委托调用底层的计算结果即可,从根源避免数据不一致。 - 缓存计算结果:在
LogicStatement内部缓存计算后的Expression和Value,确保只执行一次计算,兼顾性能与结果一致性。 - 正确的对象关联:Dapper加载数据时,必须保证层级对象(Literal→Test→LogicStatement)是真实关联的,而非用空对象覆盖后丢失关联关系。
具体实现步骤
1. 重构LogicStatement,实现结果缓存
public class LogicStatement : ILogicStatement { public string TestLogic { get; set; } public string CompareLogic { get; set; } public string Operator { get; set; } // 用私有字段缓存计算结果,避免重复计算 private string _cachedExpression; private bool? _cachedValue; public string Expression() { if (_cachedExpression == null) { // 这里替换成你的实际计算逻辑 _cachedExpression = $"{TestLogic} {Operator} {CompareLogic}"; } return _cachedExpression; } public bool Value() { if (_cachedValue == null) { // 这里替换成你的实际布尔值计算逻辑 _cachedValue = bool.TryParse(Expression(), out var result) ? result : false; } return _cachedValue.Value; } }
2. 重构Test类,移除冗余存储,直接委托
public class Test : ITest { public int TestId { get; set; } public int LiteralId { get; set; } public string TestName { get; set; } public string TestText { get; set; } public string TestDisplayName { get; } public ILogicStatement LogicStatement { get; set; } // 不再本地存储,直接返回LogicStatement的计算结果 public string Expression => LogicStatement?.Expression() ?? string.Empty; public bool Value => LogicStatement?.Value() ?? false; public Test(ILogicStatement logicStatement) { LogicStatement = logicStatement; } }
3. 重构Literal类,同理委托到Test层级
public class Literal : ILiteral { // 其他属性成员... public List<ITest> Tests {get; set;} // 根据业务需求定义Literal的Expression/Value,比如取第一个Test的结果 public string Expression => Tests?.FirstOrDefault()?.Expression ?? string.Empty; public bool Value => Tests?.FirstOrDefault()?.Value ?? false; public Literal(List<ITest> tests) { Tests = tests; } }
4. 修正主代码的实例化逻辑
不需要提前用Factory创建空列表,直接让Dapper返回关联好的完整对象层级:
// 直接从Dapper获取关联完成的对象,无需提前创建空列表 List<ILiteral> literals = GetDataFromDapper();
如果Dapper需要自定义对象创建逻辑,可以配置它使用你的Factory来生成LogicStatement和Test实例,确保依赖注入的正确性。
关键要点说明
- 无冗余存储:上级类不保留
Expression和Value的副本,始终从底层获取,永远不会出现数据不一致。 - 一次计算多次复用:
LogicStatement的缓存机制确保计算只执行一次,后续调用直接返回缓存值。 - 对象关联是核心:Dapper必须正确构建Literal→Test→LogicStatement的关联链,否则上级类无法获取到有效的
LogicStatement实例,自然返回null。
内容的提问来源于stack exchange,提问作者waza

