2017-07-05 2 views
2

Betrachten wir zwei Ausdrucksbäume:Expression Bäume - Ersatz Ausdruck

Expression<Func<float, float, float>> f1 = (x, y) => x + y; 
Expression<Func<float, float>> f2 = x => x * x; 

ich den Ausdruck f2 als zweiten Parameter von f1 und erhalten den folgenden Ausdruck ersetzen wollen:

Expression<Func<float, float, float>> f3 = (x, y) => x + y * y; 

Der einfachste Weg ist zu verwenden Expression.Lambda und Expression.Invoke, aber das Ergebnis wird wie

(x, y) => f1(x, f2(y)) 
aussehen

Aber das ist inakzeptabel für mich aufgrund von ORM-Einschränkungen, die nicht richtig mit invoke/lambda umgehen können.

Ist es möglich, den Ausdruck ohne vollständige Traversierung von Expressionsbäumen zu konstruieren? Ein funktionierendes Beispiel, das meine Bedürfnisse erfüllt, kann here gefunden werden, aber ich möchte einfachere Lösung.

+0

ohne vollständige Durchquerung Ausdrucksbäume - nein. Grundsätzlich benötigen Sie den Parameter Replacer, der mit ExpressionVisitor implementiert wird. –

Antwort

2

Sie können es nicht ohne vollständiges Durchlaufen beider Ausdrücke tun. Glücklicherweise macht ExpressionVisitor voll Traversal einfach:

class ReplaceParameter : ExpressionVisitor { 
    private readonly Expression replacement; 
    private readonly ParameterExpression parameter; 
    public ReplaceParameter(
     ParameterExpression parameter 
    , Expression replacement 
    ) { 
     this.replacement = replacement; 
     this.parameter = parameter; 
    } 
    protected override Expression VisitParameter(ParameterExpression node) { 
     return node == parameter ? replacement : node; 
    } 
} 

verwenden Besucher zweimal den Austausch zu vollenden:

Expression<Func<float,float,float>> f1 = (x, y) => x + y; 
Expression<Func<float,float>> f2 = x => x * x; 
var pX = f2.Parameters[0]; 
var pY = f1.Parameters[1]; 
var replacerF2 = new ReplaceParameter(pX, pY); 
var replacerF1 = new ReplaceParameter(pY, replacerF2.Visit(f2.Body)); 
var modifiedF1 = Expression.Lambda(
    replacerF1.Visit(f1.Body) 
, f1.Parameters 
); 
Console.WriteLine(modifiedF1); 

Die obigen Drucke

(x, y) => (x + (y * y)) 

Demo.