2009-05-10 10 views
26

Wie würde ich einen Ausdruck Baum gehen über die Verwendung von dynamisch ein Prädikat zu erstellen, die ...Wie erstelle ich dynamisch einen Ausdruck <Func <MyClass, bool >> Prädikat?

(p.Length== 5) && (p.SomeOtherProperty == "hello") 

das Prädikat in einen Lambda-Ausdruck bleiben kann ...

q.Where(myDynamicExpression)... 
So, dass ich wie so etwas aussieht

Ich muss nur in die richtige Richtung zeigen.

Update: Sorry Leute, ich habe die Tatsache ausgelassen, dass ich das Prädikat mehrere Bedingungen wie oben haben möchte. Entschuldigung für die Verwirrung.

Antwort

45

Original-

Wie so:

var param = Expression.Parameter(typeof(string), "p"); 
    var len = Expression.PropertyOrField(param, "Length"); 
    var body = Expression.Equal(
     len, Expression.Constant(5)); 

    var lambda = Expression.Lambda<Func<string, bool>>(
     body, param); 

Aktualisiert

re (p.Length== 5) && (p.SomeOtherProperty == "hello"):

var param = Expression.Parameter(typeof(SomeType), "p"); 
var body = Expression.AndAlso(
     Expression.Equal(
      Expression.PropertyOrField(param, "Length"), 
      Expression.Constant(5) 
     ), 
     Expression.Equal(
      Expression.PropertyOrField(param, "SomeOtherProperty"), 
      Expression.Constant("hello") 
     )); 
var lambda = Expression.Lambda<Func<SomeType, bool>>(body, param); 
+0

Danke, aber dummerweise habe ich vergessen zu erwähnen, dass ich das Prädikat möchten, lesen sich wie ... (p.Length == 5) && (p.SomeOtherProperty == "Hallo"). Mit anderen Worten, wie kann ich die Bedingungen verketten? Entschuldigung, dass wir nicht klar waren – Senkwe

+0

Vielen Dank für das Update. Es scheint so zu sein, wonach ich gesucht habe. Dank – Senkwe

+0

@Mark Gravell: wenn wir 'SomeType' nicht haben, wie wir Lambda erstellen können. Beispiel: Wir haben nur Type 'TiepOfEntity = Assembly.GetType (string.Format (" Smartiz.Data.{0} ", EntityName));' –

0

Sie können den Ausdruck instanziieren und mit einem Expression Tree-Visualizer betrachten. Es gibt eine in den Visual Studio-Beispielen - Sie können sie kompilieren und dann in einen bestimmten Ordner legen.

Das wird Ihnen einen schönen kleinen Baum geben, der Ihnen zeigt, wie ein Ausdruck zusammengesetzt ist. Dann könnten Sie einen solchen Ausdruck mit den statischen Methoden des Expression-Objekts konstruieren.

9

Um mehrere Prädikate mit dem Operator && zu kombinieren, verbinden Sie sie zwei zu einem Zeitpunkt.

Also, wenn Sie eine Liste der Expression-Objekte haben predicates genannt, dies zu tun:

Expression combined = predicates.Aggregate((l, r) => Expression.AndAlso(l, r)); 
1

Um Lambda-Ausdruck einander zuzuordnen: Eine andere Möglichkeit ist, den folgenden Code zu verwenden. Es ist flexibler als die Schotime Antwort in meinem Rat und arbeiten perfekt. 4.0 Keine externen Nuggets benötigt

Rahmen

// Usage first.Compose(second, Expression.And) 
    public static Expression<T> Compose<T>(this Expression<T> First, Expression<T> Second, Func<Expression, Expression, Expression> Merge) 
    { 
     // build parameter map (from parameters of second to parameters of first) 
     Dictionary<ParameterExpression,ParameterExpression> map = First.Parameters.Select((f, i) => new { f, s = Second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); 

     // replace parameters in the second lambda expression with parameters from the first 
     Expression secondBody = ParameterRebinder.ReplaceParameters(map, Second.Body); 

     // apply composition of lambda expression bodies to parameters from the first expression 
     return Expression.Lambda<T>(Merge(First.Body, secondBody), First.Parameters); 
    } 

    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> First, Expression<Func<T, bool>> Second) 
    { 
     return First.Compose(Second, Expression.And); 
    } 

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> First, Expression<Func<T, bool>> second) 
    { 
     return First.Compose(second, Expression.Or); 
    } 


public class ParameterRebinder : ExpressionVisitor 
{ 
    private readonly Dictionary<ParameterExpression, ParameterExpression> map; 

    public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) 
    { 
     this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>(); 
    } 

    public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) 
    { 
     return new ParameterRebinder(map).Visit(exp); 
    } 

    protected override Expression VisitParameter(ParameterExpression p) 
    { 
     ParameterExpression replacement; 
     if (map.TryGetValue(p, out replacement)) 
     { 
      p = replacement; 
     } 
     return base.VisitParameter(p); 
    } 
} 
Verwandte Themen