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

能否使用ExpressionVisitor遍历表达式体成员并获取其Getter的Expression?

问题前置提醒

你给出的示例代码存在递归错误:LinePrice的getter访问了自身,运行时会触发无限递归导致栈溢出,正确的计算逻辑应该是Quantity * UnitPrice。


实现方案

表达式体属性(=> 定义的getter)默认编译为普通IL方法,不会直接生成可直接读取的Expression对象,你可以通过两种方案实现需求:

方案1:可修改类定义时优先使用(最稳定高效)

直接把计算逻辑封装为公开的静态表达式字段,属性直接调用编译后的表达式委托:

class OrderLine : Table
{
    public int Id { get; set; }
    public Order Order { get; set; }
    public decimal Quantity { get; set; }
    public decimal UnitPrice { get; set; }

    // 预定义计算逻辑的表达式树
    public static readonly Expression<Func<OrderLine, decimal>> LinePriceExpression = ol => ol.Quantity * ol.UnitPrice;
    // 缓存编译后的委托,避免重复编译损耗
    private static readonly Func<OrderLine, decimal> _linePriceGetter = LinePriceExpression.Compile();

    [CalculatedField]
    public decimal LinePrice => _linePriceGetter(this);
}

需要读取表达式时,通过反射拿到对应静态字段即可:

var calculatedProp = typeof(OrderLine).GetProperties()
    .First(p => p.GetCustomAttribute<CalculatedFieldAttribute>() != null);
// 按约定读取对应表达式字段
var exprField = typeof(OrderLine).GetField($"{calculatedProp.Name}Expression", BindingFlags.Public | BindingFlags.Static);
var linePriceExpr = (LambdaExpression)exprField.GetValue(null);

拿到的linePriceExpr可以直接传给ExpressionVisitor遍历,完全符合你构建远程请求的需求。

方案2:不可修改类定义时使用

如果不能调整现有类的代码,你需要通过IL反解析把属性getter的IL代码转换为Expression树:

  1. 先通过反射获取属性的get方法:
    var getMethod = typeof(OrderLine).GetProperty("LinePrice").GetMethod;
    
  2. 用IL解析工具读取get方法的指令流,还原为对应的表达式节点。自己完整实现IL到表达式的转换逻辑复杂度很高,你可以复用成熟的开源转换组件完成这一步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 12:24:05