2013-08-29 15 views
27
Func<T, bool> expr = x => x.Prop != 1; 

somelist = somelist.Where(expr); 

So weit so gut. Aber ich möchte expr wie diese negieren:Negieren Func <T, bool> in Lambda-Ausdruck

somelist = somelist.Where(!expr); 

, die in einem Compiler-Fehler führen: Cannot apply ! operator to operand of type Func<T, bool>.

Muss ich eine andere Ausdrucksvariable dafür erstellen?

Func<T, bool> expr2 = x => x.Prop == 1; 

Antwort

48
Func<T, bool> expr = x => x.Prop != 1; 

Func<T, bool> negativeExpr = value => !expr(value); 

oder

somelist = somelist.Where(value => !expr(value)); 

Wenn die Expression Bäume mit dem folgenden den Trick:

Expression<Func<T, bool>> expr = x => x.Prop != 1; 

var negativeExpr = Expression.Lambda<Func<T, bool>>(
    Expression.Not(expr.Body), 
    expr.Parameters); 

somelist = somelist.Where(negativeExpr); 

Um Ihnen das Leben zu erleichtern, können Sie die folgenden Erweiterungsmethoden erstellen:

public static Func<T, bool> Not<T>(
    this Func<T, bool> predicate) 
{ 
    return value => !predicate(value); 
} 

public static Expression<Func<T, bool>> Not<T>(
    this Expression<Func<T, bool>> predicate) 
{ 
    return Expression.Lambda<Func<T, bool>>(
     Expression.Not(expr.Body), 
     expr.Parameters); 
} 

Jetzt können Sie dies tun:

somelist = somelist.Where(expr.Not()); 
18

Ich bin nur diese dort als dumme Antwort gehen zu werfen. Nur um klar zu sein: Ich würde das nicht tun, und ich empfehle niemandem das. :)

Ich wollte irgendwie sehen, ob es möglich ist, die somelist.Where(!expr) Syntax oder so etwas zu bekommen.

Nun, mir ist gelungen, und ich hasse mich.

var expr = N.egatable<MyClass>(x => x.Prop != 1); 
somelist = someList.Where(!expr); 

Die N.egatable war nur ein kleiner Helfer Bequemlichkeit Syntax und weitgehend überflüssig (EDIT: Ich wollte MyClass explizit zu vermeiden, zu definieren, oder irgendwie die Instanziierung des Objekts Wrapper machen versteckt, aber ganz konnte nicht und es dachte, vielleicht würde jemand eine bessere Idee):

public static class N 
{ 
    public static Negator<T> egatable<T>(Func<T, bool> underlyingFunction) 
    { 
     return new Negator<T>(underlyingFunction); 
    } 
} 

Negator<T> ist, wo die wirkliche „Magie“ geschieht:

public class Negator<T> 
{ 
    private Func<T, bool> UnderlyingFunction; 

    public Negator(Func<T, bool> underlyingFunction) 
    { 
     this.UnderlyingFunction = underlyingFunction; 
    } 

    public static implicit operator Func<T, bool>(Negator<T> neg) 
    { 
     return v => neg.UnderlyingFunction(v); 
    } 

    public static Negator<T> operator !(Negator<T> neg) 
    { 
     return new Negator<T>(v => !neg.UnderlyingFunction(v)); 
    } 
} 

Zuerst führt die Operatorüberladung ! die Funktion Negation aus (genau wie in this answer), dann kann der implizite Konvertierungsoperator Func<T, bool> die Erweiterungsmethode Where übergeben.

Vielleicht sehr dumm ist, dass Sie halten es hin und her wie das Spiegeln:

somelist = someList.Where(!!expr); 
somelist = someList.Where(!!!expr); 
somelist = someList.Where(!!!!expr); 
somelist = someList.Where(!!!!!expr); 
somelist = someList.Where(!!!!!!expr); //oh my what 

Also noch einmal ... Bitte tun Sie das nicht. :) Bleiben Sie unbedingt auf die richtige Art und Weise, Dinge zu tun, wie in Steven's Antwort.

EDIT: Hier ist eine Implementierung mit Ausdrücken, die die gleiche Weise in Bezug auf Syntaxnutzung funktioniert.Nicht sicher, ob es "korrekt" ist und es nicht gegen Entity Framework getestet:

public class ExpressionNegator<T> 
{ 
    private Expression<Func<T, bool>> UnderlyingExpression; 

    public ExpressionNegator(Expression<Func<T, bool>> underlyingExpression) 
    { 
     this.UnderlyingExpression = underlyingExpression; 
    } 

    public static implicit operator Func<T, bool>(ExpressionNegator<T> neg) 
    { 
     return neg.UnderlyingExpression.Compile(); 
    } 

    public static implicit operator Expression<Func<T, bool>>(ExpressionNegator<T> neg) 
    { 
     return neg.UnderlyingExpression; 
    } 

    public static ExpressionNegator<T> operator !(ExpressionNegator<T> neg) 
    { 
     var originalExpression = neg.UnderlyingExpression; 
     Expression<Func<T, bool>> negatedExpression = originalExpression.Update(
      Expression.Not(originalExpression.Body), 
      originalExpression.Parameters); 
     return new ExpressionNegator<T>(negatedExpression); 
    } 
} 
+0

Sorry, Sie mehr zu foltern, weil ich weiß, dass das wahrscheinlich bei Ihnen essen wird, bis Sie es zur Arbeit bekommen (ich war Dort). Ich frage mich, ob Sie es mit einem 'Expression > auch arbeiten lassen können, damit es mit Linq2Entity-Providern wie Entity Framework funktioniert. –

+1

@ScottChamberlain: Ich könnte es wahrscheinlich mit Ausdrücken tun, aber ich weiß nicht, ob es eine kompatible _runtime_ Ausführung für Entitäten übersetzen würde (ich nehme an, es könnte _might_ sein, was sind ein paar zusätzliche Negationen für eine SQL-Abfrage?). Vielleicht werde ich es in meiner Freizeit versuchen. –

+0

Wenn Sie ein Lambda in sein Gegenteil umwandeln möchten, können Sie einfach schreiben, mit der Variablen 'Expression > originalLambda',' Expression > negatedLambda = originalLambda.Update (Expression.Not (originalLambda.Body), originalLambda .Parameters); ' –

Verwandte Themen