2013-03-26 4 views
1

У меня есть два выражения:Выбор из лямбда-выражения с лямбда-выражения

public static Expression<Func<TSource, TReturn>> Merge<TSource, TSource2, TReturn>(
     Expression<Func<TSource, TSource2>> foo1 
     Expression<Func<TSource2, TReturn>> foo2) 
    { 
     // What to do? 
    } 

Как я могу объединить их в единое выражение, поэтому выход из первого используется в качестве входного сигнала для второго? Я новичок в них, и до сих пор это были только исключения.

Благодаря

+0

Вы можете добавить конкретный пример, который показывает, что вы имеете в виду? это как в 'x => x.Name' и' s => s.Length', чтобы получить 'x => x.Name.Length'? –

+0

Да, извините, это то, что я имел в виду, для будущей справки, когда люди приходят к этому. – Tim

ответ

1

Это во многом зависит, какие поставщики должны использовать его. Некоторое будет хорошо:

public static Expression<Func<TSource, TReturn>> 
    Merge<TSource, TSource2, TReturn>(
    Expression<Func<TSource, TSource2>> foo1, 
    Expression<Func<TSource2, TReturn>> foo2) 
{ 
    return Expression.Lambda<Func<TSource, TReturn>>(
     Expression.Invoke(foo2, foo1.Body), 
     foo1.Parameters); 
} 

Однако, другие (EF) не будут. Вы также можете переписать дерево выражений с посетителем, чтобы вставить выражение:

public static Expression<Func<TSource, TReturn>> 
     Merge<TSource, TSource2, TReturn>(
    Expression<Func<TSource, TSource2>> foo1, 
    Expression<Func<TSource2, TReturn>> foo2) 
{ 
    var swapped = new SwapVisitor(
     foo2.Parameters.Single(), foo1.Body).Visit(foo2.Body); 
    return Expression.Lambda<Func<TSource, TReturn>>(
     swapped, foo1.Parameters); 
} 

class SwapVisitor : ExpressionVisitor 
{ 
    private readonly Expression from, to; 
    public SwapVisitor(Expression from, Expression to) 
    { 
     this.from = from; 
     this.to = to; 
    } 
    public override Expression Visit(Expression node) 
    { 
     return node == from ? to : base.Visit(node); 
    } 
} 

это будет работать со всеми поставщиками.

+0

Это действительно сработало! Спасибо, я был очень близок, но я использовал foo1, а не foo1.Body в моей перегрузке Invoke. – Tim

+0

@ См. Редактирование; как правило, предпочтительнее, поскольку он будет работать в большем количестве мест (и может быть более прямым). –

+0

Также спасибо за расширенный ответ. Я использую LINQ-to-Entities, поэтому, вероятно, это будет полезно в будущем. Редактировать: Хорошо спасибо! – Tim

Смежные вопросы