2016-03-04 3 views
0

Я хотел бы использовать один лямбда-выражение в качестве аргумента метода Enumerable.Select, и добавить это как новое связывание с лямбда-выражения родителя, как показано:включая детский дерево выражения с вызовом Enumerable.Select

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

Это очень похоже на ваш предыдущий вопрос. Глядя на

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") из 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)); 
     } 
    } 

}

и использование образца:

var expressionIGet = MapFoo.AddCollectionMap(MapBar, "Bars");