2012-12-20 15 views
6

Mam 3 predykaty, chciałbym dokonać AndAlso między. Znalazłem kilka próbek na tablicy, ale nie mogę rozwiązać mojego problemu.AndAlso między kilkoma wyrażeń <Func <T, bool>>: odwołuje się z zakresu

te predykaty są: Expression<Func<T, bool>>

mam ten kod:

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

utworzyć metodę rozszerzenia do dokonania "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]); 
} 

używam tak:

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

Predykat wyglądać następująco: enter image description here

Kiedy używać w zapytaniu:

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

otrzymuję ten błąd: zmienną 'p' typu 'BuilderPredicate.MyClass' odwołuje się od zakresu '' , ale nie jest zdefiniowany

Czy możesz mi powiedzieć, co jest nie tak?

Dzięki dużo,

Odpowiedz

10

Problemem jest stworzenie nowego parametru - można to zrobić, ale jeśli po prostu przypisać go do ostatecznego lambda, nie ma połączenia między parametrem i oryginalnych parametrów w określonych wyrażeń . Spróbuj zmienić nazwy parametrów wyrażeń, a następnie sprawdź numer finalPredicate. Zobaczysz coś takiego:

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

Problem powinien być teraz oczywisty.

Marc Gravell sugerować w this answer ogólny Expression.AndAlso, która jest dokładnie to, czego potrzebujesz:

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

(kod Marc, nie ja)

+1

widziałem kod Marca, ale nie działa nie pamiętam dlaczego. Ale próbuję teraz agresji –

+1

Wypróbuj i daj mi znać, jeśli to nie działa - zadziałało dla mnie (musisz tylko upewnić się, że jest dostępny dla twojego kodu, tj. Publiczny lub wewnętrzny, zmienię to w mojej odpowiedzi) –

+0

Tak, to jest praca. Nie wiem, co zrobiłem w poprzednim teście. Ale szczerze mówiąc, nie jest dla mnie jasne, jak to wszystko działa :) –

Powiązane problemy