2009-05-10 9 views
26

Come potrei fare per utilizzare un albero di espressione per creare dinamicamente un predicato che sembra qualcosa di simile ...Come creare dinamicamente un'espressione <Func <MyClass, bool >> predicato?

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

In modo che posso attaccare il predicato in un'espressione lambda in questo modo ...

q.Where(myDynamicExpression)... 

Ho solo bisogno di essere puntato nella giusta direzione.

Aggiornamento: Scusate, ho omesso il fatto che voglio che il predicato abbia più condizioni come sopra. Dispiace per la confusione.

risposta

45

originale

Come così:

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

Aggiornato

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

Grazie, ma stupidamente ho dimenticato di dire che mi piacerebbe il predicato per leggere come ... (p.Length == 5) && (p.SomeOtherProperty == "ciao"). In altre parole, come concatenare le condizioni? Ci scusiamo per non essere stato chiaro – Senkwe

+0

Grazie mille per l'aggiornamento. Sembra essere quello che stavo cercando. Grazie – Senkwe

+0

@Mark Gravell: se non avessimo 'SomeType' come possiamo creare lambda. Ad esempio, abbiamo appena digitato 'TyepOfEntity = Assembly.GetType (string.Format (" Smartiz.Data.{0} ", EntityName));' –

0

È possibile creare un'istanza dell'espressione e visualizzarla con un visualizzatore di Albero espressioni. Ce n'è uno negli esempi di Visual Studio: puoi compilarlo e poi inserirlo in una cartella specifica.

Questo ti darà un grazioso alberello che ti mostra come viene composta un'espressione. Quindi è possibile costruire un'espressione di questo tipo con i metodi statici dell'oggetto Expression.

9

Per combinare più predicati con l'operatore &&, li si unisce insieme due alla volta.

Quindi, se si dispone di un elenco di oggetti espressione chiamati predicates, fare questo:

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

Per associare l'espressione Lambda a vicenda: Un altro modo è utilizzare il seguente codice. È più flessibile della risposta Schotime nel mio consiglio e funziona perfettamente. Nessun Nuggets esterni necessari

Framework 4,0

// 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); 
    } 
} 
Problemi correlati