2012-12-20 13 views
6

Ich habe 3 Prädikate, ich möchte eine AndAlso zwischen machen. Ich habe mehrere Beispiele auf dem Board gefunden, kann aber mein Problem nicht lösen.AndAlso zwischen mehreren Ausdruck <Func <T, bool>>: referenziert von Bereich

Diese Prädikate sind: Expression<Func<T, bool>>

Ich habe diesen Code:

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

Ich erstelle eine Erweiterungsmethode eine "AndAlso" zu machen:

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

ich wie folgt verwenden:

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

Das Prädikat aussehen: enter image description here

Wenn ich in einer Abfrage verwenden:

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

ich diesen Fehler: Variable 'p' vom Typ 'BuilderPredicate.MyClass' von Umfang verwiesen wird '' aber es ist nicht definiert

Können Sie mir sagen, was los ist?

Vielen Dank,

Antwort

10

Das Problem einen neuen Parameter schafft - Sie tun können, aber wenn Sie es einfach auf das endgültige Lambda zuweisen, gibt es keine Verbindung zwischen dem Parameter und dem ursprünglichen Parameter in dem dafür vorgesehenen Ausdrücke . Versuchen Sie, die Parameternamen der Ausdrücke zu ändern, und überprüfen Sie dann die finalPredicate. Sie werden etwas wie sehen:

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

Das Problem sollte jetzt offensichtlich sein.

Marc GRA vorschlagen in this answer eine allgemeine Expression.AndAlso, das ist genau das, was Sie brauchen:

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

(Code von Marc, mich nicht)

+1

ich Marcs Code sah, aber hat nicht funktioniert erinnere mich nicht, warum. Aber ich versuche jetzt agrain –

+1

Versuchen Sie es und lassen Sie mich wissen, wenn es nicht funktioniert - es funktionierte für mich (Sie müssen nur sicherstellen, dass es für Ihren Code zugänglich ist, dh öffentlich oder intern; Ich werde das in meiner Antwort ändern) –

+0

Ja, das ist Arbeit. Ich weiß nicht, was ich in meinem vorherigen Test gemacht habe. Aber um ehrlich zu sein, es ist nicht sehr klar in meinem Kopf, wie all das funktioniert :) –

Verwandte Themen