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

使用Evaluator.cs仍无法解析表达式变量常量,求问题排查

问题原因及修复方案

核心问题

你的代码存在两个关键错误:

  1. 部分求值时机错误:未对Where传入的整个表达式做整体求值,导致编译器生成的局部变量包装匿名类仍留在表达式树中。
  2. VisitMember处理逻辑错误:即便对m.Expression执行了PartialEval,也未用求值后的常量替换原表达式节点,更没有将常量值写入SQL。

修复步骤

1. 先对整个Where表达式做部分求值

修改Where方法,在传入Visitor前先对整个表达式执行PartialEval,将所有可计算节点(包括包装局部变量的匿名类成员)替换为常量:

public virtual SqlBuilder<T> Where(Expression<Func<T, bool>> expression)
{
    // 先对整个表达式做部分求值,消除匿名类包装
    var evaluatedExpression = Evaluator.PartialEval(expression);
    BuiltObject.Append(" WHERE");
    ExpressionToSQLVisitor<T> expressionToSQL = new(this);
    expressionToSQL.Visit(evaluatedExpression);
    return this;
}

2. 修正VisitMember的常量处理逻辑

当处理ExpressionType.Constant类型的成员访问时,直接获取求值后的常量值并写入SQL,而非返回原MemberExpression:

protected override Expression VisitMember(MemberExpression m)
{
    if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter)
    {
        sqlBuilder.AddColumn(m.Member.GetFieldName());
        return m;
    }
    else if (m.Expression != null)
    {
        // 对整个MemberExpression做求值,得到实际常量
        var constantExpr = Evaluator.PartialEval(m) as ConstantExpression;
        if (constantExpr != null)
        {
            // 将常量值写入SQL,注意需处理字符串转义、类型适配等逻辑
            sqlBuilder.AddValue(constantExpr.Value);
            return constantExpr;
        }
        throw new NotSupportedException($"无法解析成员 '{m.Member.Name}' 的值");
    }

    throw new NotSupportedException($"不支持成员 '{m.Member.Name}'");
}

原代码失效原因

C#编译器捕获lambda中的局部变量时,会自动生成匿名类存储该变量,因此你写的obj.Name == name会被编译为obj.Name == <>匿名类.name。

你之前仅对m.Expression(匿名类实例的ConstantExpression)做PartialEval,得到的仍是匿名类实例,并未解析到字段值。只有对整个访问匿名类字段的MemberExpression执行PartialEval,才能拿到真正的常量值;同时必须将该值写入SQL,而非返回原节点,才能让SQL构建器生成Name = 'Test1'这类正确语句。

内容的提问来源于stack exchange,提问作者Aren Devel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 19:30:00