2010-12-11 13 views
17

Ich suche nach einer Möglichkeit, einen Ausdruck zu negieren, der zum Filtern von IQueryable Sequenzen verwendet wird.C# Negieren eines Ausdrucks

Also, ich habe so etwas wie:

Expression<Func<T, bool>> expression = (x => true); 

Nun wünsche ich den Ausdruck zu schaffen, die in Nachgeben (x => false) führen würde - also im Grunde negieren ich die expression wollen.

Die Arbeitsweise ich gefunden habe, funktioniert selbst wie folgt aus:

var negatedExpression = 
    Expression.Lambda<Func<T, bool>> (Expression.Not(expression.Body), 
            expression.Parameters[0]))); 

Aber ich bin fast sicher, dass es einen besseren Weg - ihr mir helfen könntet? (etwas wie Not(expression), wahrscheinlich).

Antwort

17

Eine einfache Erweiterung Methode:

public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> one) 
{ 
    var candidateExpr = one.Parameters[0]; 
    var body = Expression.Not(one.Body); 

    return Expression.Lambda<Func<T, bool>>(body, candidateExpr); 
} 

Verbrauch:

Expression<Func<int, bool>> condition = x => x > 5; 
var source = Enumerable.Range(1, 10); 
var result1 = source.Where(condition.Compile()); //6,7,8,9,10 
var result2 = source.Where(condition.Not().Compile()); //1,2,3,4,5 
+0

Nun, ich weiß, wie ich meine Aussage in eine "Nicht" -Methode umwandeln kann, aber ich suchte eigentlich nach einer einfachen Möglichkeit, die Negation tatsächlich auszuführen * (es sieht für mich so aus, dass ich 'Expression.Lambda. Blablabla ist ein riesiger Overkill. * –

+2

Expression Trees sind unveränderbar, also müssen Sie ein neues Lambda erstellen. –

-2

Was ist damit?

Expression<Func<bool>> expr =() => true; 
Expression<Func<bool>> negated =() => !expr.Compile()(); 
+0

Sie haben den Eingabeausdruck einfach in einen undurchsichtigen Methodenaufruf umgewandelt. Dies hilft überhaupt nicht, da der Zweck der Verwendung eines Ausdrucks darin besteht, dass die bereitgestellte Abfrage ihn verstehen kann. – CodesInChaos

1

Posting für die Zukunft.

Danny Chens Antwort kann allgemeinere gemacht werden:

public static Expression<TFunc> Not<TFunc>(this Expression<TFunc> baseExpr) 
{ 
    var param = baseExpr.Parameters; 
    var body = Expression.Not(baseExpr.Body); 
    var newExpr = Expression.Lambda<TFunc>(body, param); 
    return newExpr; 
} 

Diese Version kann einen Ausdruck mit einer beliebigen Anzahl von Eingabeparametern erhalten. Es fügt jedoch nur eine geringe Nutzbarkeit hinzu, da der Ausdruck wahrscheinlich sowieso an eine Funktion wie IEnumerable.Where übergeben wird.