2013-05-29 5 views
13

Ich habe so etwas wieVon Binary zu Expression <Func <T, bool>>

Angenommen
Expression<Func<SomeType, DateTime>> left = x => x.SomeDateProperty; 
Expression<Func<SomeType, DateTime>> right = x => dateTimeConstant; 
var binaryExpression = Expression.GreaterThan(left, right); 
Expression<Func<SomeType, bool>> predicate = 
          x => x.SomeDateProperty> dateTimeConstant; 

1) Wie kann ich die rechte Hand der Zuordnung der letzten Zeile mit etwas ersetzen, das die binaryExpression verwendet stattdessen? var predicate = x => binaryExpression; funktioniert nicht.

2) Die right ist immer eine Konstante, nicht unbedingt DateTime.Now. Könnte es einfacher sein als Expression? Zum Beispiel hängt es nicht von SomeType ab, es ist nur eine Konstante.

3) Wenn ich die GreaterThan als string habe, gibt es eine Möglichkeit, von dieser Zeichenfolge auf die Methode mit dem gleichen Namen in Expression zu erhalten? Wenn der Name der Vergleichsmethode als string angegeben wird, wie kann ich in der Expression-Klasse allgemein von der Zeichenfolge zu dem Aufrufen der Methode mit dem gleichen Name gehen?

Es muss mit LINQ zu Entities arbeiten, wenn es darauf ankommt.

+0

Sie können Expression-Bäume mithilfe der ExpressionVisitor-Klasse ändern. – Steven

Antwort

13

1 und 2: Sie müssen den Ausdrucksbaum manuell erstellen, um dies zu tun, der Compiler kann nicht helfen, da es nur fertige Ausdrücke erstellt, die Funktionen in ihrer Gesamtheit darstellen. Das ist nicht nützlich, wenn Sie Funktionen Stück für Stück aufbauen wollen.

Hier ist eine einfache Möglichkeit, den Ausdruck, den Sie bauen wollen:

var argument = Expression.Parameter(typeof(SomeType)); 
var left = Expression.Property(argument, "SomeDateProperty"); 
var right = Expression.Constant(DateTime.Now); 

var predicate = Expression.Lambda<Func<SomeType, bool>>(
    Expression.GreaterThan(left, right), 
    new[] { argument } 
); 

Sie können dies für eine Probefahrt mit

var param = new SomeType { 
    SomeDateProperty = DateTime.Now.Add(TimeSpan.FromHours(-1)) 
}; 

Console.WriteLine(predicate.Compile()(param)); // "False" 

3: Da aller Wahrscheinlichkeit nach der Anzahl der möglichen Optionen für Ihr binäres Prädikat ist ziemlich klein, Sie könnten dies mit einem Wörterbuch tun:

Dann statt Expression.GreaterThan im ersten Snippet zu kodieren, würden Sie etwas wie wordToExpression["GreaterThan"](left, right) tun.

Natürlich kann dies auch der Standard Weg mit Reflexion getan werden.

7

Wenn Sie GreaterThan verwenden, müssen Sie den Ausdruck Körper, nicht das Lambda selbst angeben. Leider gibt es eine Komplikation: Die x in den beiden Ausdrücken ist nicht das gleiche.

In diesem insbesondere Fall könnten Sie nur mit dieser erhalten etwa weg, weil der zweite Ausdruck nicht x nicht verwendet

So;

:

var binaryExpression = Expression.GreaterThan(left.Body, right.Body); 
    var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression, 
     left.Parameters); 

jedoch zu handhaben dies im allgemeinen Fall, müssen Sieumschreiben die Parameter auf der Ausdrücke, fixieren-up: Ihre „1“ und „2“ soll beantwortet werden

var binaryExpression = Expression.GreaterThan(left.Body, new SwapVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body)); var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression, left.Parameters); 

mit:

public 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); 
    } 
} 

Für Ihre "3"; da ist nichts eingebaut; Sie könnten jedoch auch reflection verwenden:

string method = "GreaterThan"; 

var op = typeof(Expression).GetMethod(method, 
    BindingFlags.Public | BindingFlags.Static, 
    null, new[] { typeof(Expression), typeof(Expression) }, null); 

var rightBody = new SwapVisitor(right.Parameters[0], 
    left.Parameters[0]).Visit(right.Body); 
var exp = (Expression)op.Invoke(null, new object[] { left.Body, rightBody }); 

var lambda = Expression.Lambda<Func<SomeType, bool>>(exp, left.Parameters); 
Verwandte Themen