2012-12-20 7 views
6

Ho 3 predicati, mi piacerebbe fare un AndAlso tra. Ho trovato diversi campioni sulla lavagna, ma non posso risolvere il mio problema.AndInso tra più espressioni <Func <T, bool>>: referenziato dall'ambito

Questi predicati sono: Expression<Func<T, bool>>

ho questo codice:

Expression<Func<T, bool>> predicate1 = ......; 
Expression<Func<T, bool>> predicate2 = ......; 
Expression<Func<T, bool>> predicate3 = ......; 

ho creare un metodo di estensione per fare un "AndAlso":

public static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr, 
    Expression<Func<T, bool>> exprAdd) 
{ 
    var param = Expression.Parameter(typeof(T), "p"); 
    var predicateBody = Expression.AndAlso(expr.Body, exprAdd.Body); 
    return Expression.Lambda<Func<T, bool>>(predicateBody, param); 

    //Tried this too 
    //var body = Expression.AndAlso(expr.Body, exprAdd.Body); 
    //return Expression.Lambda<Func<T, bool>>(body, expr.Parameters[0]); 
} 

io uso come questo:

var finalPredicate = predicate1 
    .AndAlso<MyClass>(predicate2) 
    .AndAlso<MyClass>(predicate3); 

Il predicato guardare questo: enter image description here

Quando uso in una query:

var res = myListAsQueryable().Where(finalPredicate).ToList<MyClass>(); 

ottengo questo errore: variabile 'p' di tipo 'BuilderPredicate.MyClass' fatto riferimento dal campo di applicazione '' , ma non è definito

Potrebbe dirmi cosa c'è che non va?

Grazie mille,

risposta

10

Il problema è la creazione di un nuovo parametro - si può fare, ma se semplicemente assegnare al lambda finale, non c'è alcuna connessione tra il parametro ei parametri originali nelle espressioni previste . Prova a cambiare i nomi dei parametri delle espressioni e poi controlla il finalPredicate. Verrà visualizzato qualcosa del tipo:

{p => (((x.Age == 42) AndAlso (y.Salary == 50)) AndAlso z.FirstName.StartsWith("foo"))} 

Il problema dovrebbe essere ovvio ora.

Marc Gravell suggeriscono in this answer un generale Expression.AndAlso, che è esattamente quello che vi serve:

public static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr1, 
    Expression<Func<T, bool>> expr2) 
{ 
    // need to detect whether they use the same 
    // parameter instance; if not, they need fixing 
    ParameterExpression param = expr1.Parameters[0]; 
    if (ReferenceEquals(param, expr2.Parameters[0])) 
    { 
     // simple version 
     return Expression.Lambda<Func<T, bool>>(
      Expression.AndAlso(expr1.Body, expr2.Body), param); 
    } 
    // otherwise, keep expr1 "as is" and invoke expr2 
    return Expression.Lambda<Func<T, bool>>(
     Expression.AndAlso(
      expr1.Body, 
      Expression.Invoke(expr2, param)), param); 
} 

(codice di Marc, non io)

+1

Ho visto il codice di Marc, ma non ha funzionato non ricordo perché Ma provo ad agrain ora –

+1

Provalo e fammi sapere se non funziona - ha funzionato per me (devi solo assicurarti che sia accessibile al tuo codice, cioè pubblico o interno; lo cambierò nella mia risposta) –

+0

Sì, questo è lavoro. Non so cosa ho fatto nel mio test precedente. Ma ad essere onesti, non è molto chiaro nella mia mente come funziona tutto questo :) –