我想使用一个lambda表达式作为Enumerable.Select方法的参数,并将其作为新的绑定添加到父lambda表达式,如下所示:
Expression<Func<Bar, BarDto>> MapBar = b => new BarDto { BarInt = b.BarInt };
Expression<Func<Foo, FooDto>> MapFoo = f => new FooDto { FooInt = f.FooInt };
Expression<Func<Foo, FooDto>> expressionIWant = f => new FooDto
{
FooInt = f.FooInt,
Bars = f.Bars.Select(b => new BarDto { BarInt = b.BarInt })
};
我到目前为止所处:
我有一个ExpressionVisitor包含:
protected override Expression VisitMemberInit(MemberInitExpression node)
{
var newBindings = new[]
{
Expression.Bind(_pi, _newExpr),
};
node = node.Update(
node.NewExpression,
node.Bindings.Concat(newBindings));
return node;
}
我显然需要包含一些
的内容var typeArgs = _originalChildExpression.Type.GenericTypeArguments;
_newExpr = Expression.Call(typeof(Enumerable),"Select",typeArgs,???source???,
_originalChildExpression);
哪里???来源???代表顶部f.Bars
中的expressionIWant
。怎么能实现这一目标?非常感谢你。
答案 0 :(得分:1)
它与您之前提出的问题非常相似。看着
Expression<Func<Foo, FooDto>> expressionIWant = f => new FooDto
{
FooInt = f.FooInt,
Bars = f.Bars.Select(b => new BarDto { BarInt = b.BarInt })
};
您可以看到f.Bars
是Property("Bars")
的{{1}}。
因此整个方法可能是这样的:
Parameter("f")
}
和样本用法:
public static class ExpressionUtils
{
public static Expression<Func<T, TMap>> AddCollectionMap<T, TMap, U, UMap>(
this Expression<Func<T, TMap>> parent,
Expression<Func<U, UMap>> nav,
string propName)
{
var parameter = parent.Parameters[0];
var target = typeof(TMap).GetProperty(propName);
var source = Expression.Property(parameter, propName);
var binding = Expression.Bind(target, Expression.Call(
typeof(Enumerable), "Select", nav.Type.GenericTypeArguments, source, nav));
var body = parent.Body.AddMemberInitBindings(binding);
return Expression.Lambda<Func<T, TMap>>(body, parameter);
}
static Expression AddMemberInitBindings(this Expression expression, params MemberBinding[] bindings)
{
return new AddMemberInitBindingsVisitor { Bindings = bindings }.Visit(expression);
}
class AddMemberInitBindingsVisitor : ExpressionVisitor
{
public MemberBinding[] Bindings;
protected override Expression VisitMemberInit(MemberInitExpression node)
{
return node.Update(node.NewExpression, node.Bindings.Concat(Bindings));
}
}