2013-08-29 35 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);' –