2016-12-18 1 views
3

Ich habe eine Methode, die Ausdruck Expression<Func<TFoo, string>> exp ausnimmt.Verschmelzen zwei Ausdrücke des gleichen Typs (ohne bool)

kann ich einzelnen Ausdruck wie diese

MyMethod(o => o.SomeStringProperty); 

Aber jetzt will passieren i Ausdrücke kombinieren (von zwei String-Objekten) und

Jedes zweites Beispiel, das ich von Expression<Func<Foo, bool>> ist gefunden in dieser Methode übergibt.

Ich versuchte

Expression<Func<TFoo, string>> fn1 = x => x.SomeStringProperty1; 
Expression<Func<TFoo, string>> fn2 = x => x.SomeStringProperty2; 

var body = Expression.Coalesce(fn1.Body, fn2.Body); 
var lambda = Expression.Lambda<Func<TFoo, string>>(body, fn1.Parameters[0]); 

aber fast jede Funktion von Expression wirft Ausnahme. Wie macht man das kombinieren?

+0

Was meinst du mit „kombinieren“ zwei Ausdrücke? In Ihrem Beispiel rufen Sie nur eine Methode mit zwei Argumenten auf. –

+1

@IvanStoev: Meine Frage aktualisiert –

Antwort

1

Wenn Sie Lambda-Ausdrücke kombinieren, sollten Sie sicherstellen, dass sie an den gleichen Parameter Instanzen gebunden sind, die im resultierenden Ausdruck verwendet werden.

Es kann auf zwei Arten erreicht werden.

Die erste ist Expression.Invoke Methode zu verwenden:

var body = Expression.Coalesce(fn1.Body, Expression.Invoke(fn2, fn1.Parameters[0])); 
var lambda = Expression.Lambda<Func<TFoo, string>>(body, fn1.Parameters[0]); 

Dies ist die einfachste Methode, aber schafft nicht unterstützten Ausdruck für Entity Framework und ähnliche, die nicht Aufruf Ausdrücke unterstützen.

Der zweite Ansatz verwendet einen einfachen Parameter replacer Helfer den zweiten Lambda-Ausdruck Körper mit den ersten Lambda-Ausdruck Parametern erneut zu binden:

public static class ExpressionUtils 
{ 
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target) 
    { 
     return new ParameterReplacer { Source = source, Target = target }.Visit(expression); 
    } 
    class ParameterReplacer : ExpressionVisitor 
    { 
     public ParameterExpression Source; 
     public Expression Target; 
     protected override Expression VisitParameter(ParameterExpression node) 
     { 
      return node == Source ? Target : base.VisitParameter(node); 
     } 
    } 
} 

wie diese

var body = Expression.Coalesce(fn1.Body, 
    fn2.Body.ReplaceParameter(fn2.Parameters[0], fn1.Parameters[0])); 
var lambda = Expression.Lambda<Func<TFoo, string>>(body, fn1.Parameters[0]); 
Verwandte Themen