包括调用Enumerable.Select的子表达式树

时间:2016-03-04 10:26:29

标签: c# expression-trees

我想使用一个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。怎么能实现这一目标?非常感谢你。

1 个答案:

答案 0 :(得分:1)

它与您之前提出的问题非常相似。看着

Expression<Func<Foo, FooDto>> expressionIWant = f => new FooDto
{
    FooInt = f.FooInt,
    Bars = f.Bars.Select(b => new BarDto { BarInt = b.BarInt })
};

您可以看到f.BarsProperty("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));
        }
    }