如何将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,需要通过表达式树访问器替换参数并构建新的表达式。具体实现步骤如下:
- 提取
projectionSource的参数和原有初始化表达式 - 获取
Dest.Item作为目标绑定成员 - 将
projectionItem的参数替换为source.Item的表达式,生成适配Source的DestItem初始化逻辑 - 合并原有绑定与新的嵌套对象绑定,生成新的初始化表达式
- 构建最终的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
相关产品推荐
相关产品推荐

