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

somelist = somelist.Where(expr); 

到目前爲止這麼好。但我想否定expr這樣的:拉姆達表達式中的否定函數<T, bool>

somelist = somelist.Where(!expr); 

這導致編譯錯誤:Cannot apply ! operator to operand of type Func<T, bool>

我必須爲此創建另一個表達式變量嗎?

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

回答

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

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

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

當使用表達式樹下面會做的伎倆:

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

爲了使您的生活更輕鬆,你可以創建以下擴展方法:

現在10

,你可以這樣做:

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

我只是去那裏把它做爲一個答案。只是要清楚:我不會這樣做,我不建議任何人這樣做。 :)

我有點想看看是否有可能得到somelist.Where(!expr)語法或類似的東西。

好吧,我成功了,我討厭自己。

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

N.egatable只是一個小便利語法助手和大可不必(編輯:我想避免必須明確定義MyClass或以某種方式使物體的包裝隱藏的實例,但不能完全得到那裏想也許有人會有一個更好的主意):

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

Negator<T>是真正的「神奇」發生了:

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

首先,!運算符重載執行函數否定(就像在this answer中一樣),然後隱式轉換運算符爲Func<T, bool>,它允許它傳入Where擴展方法。

也許很無聊的是你可以保持翻轉來回這樣的:

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

如此反覆......請不要這樣做。 :)肯定堅持正確/理智的做法,就像史蒂文的回答一樣。

編輯:這是一個使用表達式的實現,它在語法使用方面的工作方式完全相同。不知道是否是「正確的」,並沒有測試它針對實體框架:

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

對不起,折磨你了,因爲我知道這很可能會吃你,直到你得到它的工作太(我一直那裏)。我想知道是否可以使用'Expression >'來使它與像Entity Framework這樣的Linq2Entities提供程序一起工作。 –

+1

@ScottChamberlain:我可以用表達式來完成它,但我不知道它是否會轉化爲實體的兼容_runtime_執行(我想它_might_,畢竟,對SQL查詢有什麼額外的否定?)。也許在業餘時間,我會給它一個鏡頭。 –

+0

如果您想將lambda轉換爲相反的值,可以使用變量'Expression > originalLambda','Expression > negatedLambda = originalLambda.Update(Expression.Not(originalLambda.Body),originalLambda .Parameters);' –