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

如何将MemberInitExpression添加到Lambda表达式的MemberInitExpression绑定中

问题需求

首先定义了以下类:

class Source {
    public int Id { get; set; }
    public string Name { get; set; }
    public SourceItem Item { get; set; }
}

class SourceItem {
    public Guid Id { get; set; }
    public decimal Price { get; set; }
}

class Dest {
    public int Id { get; set; }
    public string Name { get; set; }
    public DestItem Item { get; set; }
}

class DestItem{
    public Guid Id { get; set; }
    public decimal Price { get; set; }
}

并构建了如下Lambda表达式:

Expression<Func<Source, Dest>> projectionSource = source => new Dest{
    Id = source.Id,
    Name = source.Name
};

Expression<Func<SourceItem, DestItem>> projectionItem = item => new DestItem
{
    Id = item.Id,
    Price = item.Price
};

Expression<Func<Source, SourceItem>> sourceMember = source => source.Item;
Expression<Func<Dest, DestItem>> destMember = dest => dest.Item;

需要将projectionItem中的MemberInitExpression作为新的元素绑定,添加到projectionSource的元素绑定列表中,最终得到包含嵌套对象初始化的目标Lambda表达式,但尝试添加时未能成功,寻求解决方法。

解决方法

表达式树是不可变结构,无法直接修改原有的projectionSource,需要通过表达式树访问器替换参数并构建新的表达式。具体实现步骤如下:

  1. 提取projectionSource的参数和原有初始化表达式
  2. 获取Dest.Item作为目标绑定成员
  3. 将projectionItem的参数替换为source.Item的表达式,生成适配Source的DestItem初始化逻辑
  4. 合并原有绑定与新的嵌套对象绑定,生成新的初始化表达式
  5. 构建最终的Lambda表达式

完整代码示例:

using System.Linq.Expressions;

// 提取projectionSource的参数和原有初始化表达式
var sourceParam = projectionSource.Parameters[0];
var sourceInit = (MemberInitExpression)projectionSource.Body;

// 获取要绑定的Dest.Item成员
var destItemMember = (MemberExpression)destMember.Body;

// 替换projectionItem的参数:将item参数替换为source.Item的表达式
var itemParam = projectionItem.Parameters[0];
var itemInit = (MemberInitExpression)projectionItem.Body;
var replacedInit = new ExpressionReplacer(itemParam, sourceMember.Body).Visit(itemInit);

// 创建新的成员绑定
var itemBinding = Expression.Bind(destItemMember.Member, replacedInit);

// 合并原有绑定和新绑定,生成新的初始化表达式
var newBindings = sourceInit.Bindings.Concat(new[] { itemBinding });
var newInit = Expression.MemberInit(sourceInit.NewExpression, newBindings);

// 构建最终的Lambda表达式
Expression<Func<Source, Dest>> finalProjection = Expression.Lambda<Func<Source, Dest>>(newInit, sourceParam);

// 辅助类:用于替换表达式树中的指定节点
class ExpressionReplacer : ExpressionVisitor
{
    private readonly Expression _oldExpr;
    private readonly Expression _newExpr;

    public ExpressionReplacer(Expression oldExpr, Expression newExpr)
    {
        _oldExpr = oldExpr;
        _newExpr = newExpr;
    }

    public override Expression Visit(Expression node)
    {
        return node == _oldExpr ? _newExpr : base.Visit(node);
    }
}

这段代码通过自定义ExpressionVisitor完成参数替换,将原本针对SourceItem的初始化逻辑转换为针对Source.Item的嵌套初始化,最终生成包含完整对象结构的Lambda表达式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 04:15:22