You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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初学者,希望得到基础原理的解释。

解决方案与原理说明

基础原理

  1. 单向依赖与委托:既然所有Expression和Value的根源都是LogicStatement,上级类(Test、Literal)无需自己存储这些值,直接委托调用底层的计算结果即可,从根源避免数据不一致。
  2. 缓存计算结果:在LogicStatement内部缓存计算后的Expression和Value,确保只执行一次计算,兼顾性能与结果一致性。
  3. 正确的对象关联: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 17:05:45