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

somelist = somelist.Where(expr);

So far so good. But I would like to negate expr like this:

somelist = somelist.Where(!expr);

Which result in a compile error: Cannot apply ! operator to operand of type Func<T, bool>.

Do I have to create another expression variable for this?

Func<T, bool> expr2 = x => x.Prop == 1;
Johan
  • 35,120
  • 54
  • 178
  • 293

2 Answers2

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

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

or

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

When using expression trees the following will do the 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);

To make your life easier, you can create the following extension methods:

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>> expr)
{
    return Expression.Lambda<Func<T, bool>>(
        Expression.Not(expr.Body), 
        expr.Parameters);
}

Now you can do this:

somelist = somelist.Where(expr.Not());
Rand Random
  • 7,300
  • 10
  • 40
  • 88
Steven
  • 166,672
  • 24
  • 332
  • 435
18

I'm just going to throw this out there as a silly answer. Just to be clear: I would not do this, and I do not recommend that anyone does this. :)

I kind of wanted to see if it was possible to get the somelist.Where(!expr) syntax or something like it.

Well I succeeded, and I hate myself.

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

The N.egatable was just a small convenience syntax helper and largely unnecessary (EDIT: I wanted to avoid having to explicitly define MyClass or somehow make the instantiation of the object wrapper hidden, but couldn't quite get there and thought maybe someone would have a better idea):

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

Negator<T> is where the real "magic" happens:

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

First the ! operator overload performs the function negation (just as in this answer), then the implicit conversion operator to Func<T, bool> lets it pass in to the Where extension method.

Perhaps very silly is you can keep flipping it back and forth like this:

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

So again... please don't do this. :) Definitely stick to the proper/sane way of doing things as in Steven's answer.

EDIT: Here's an implementation using expressions which works the exact same way in terms of syntax usage. Not sure if it's "correct", and haven't tested it against Entity Framework:

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);
    }
}
Community
  • 1
  • 1
Chris Sinclair
  • 22,858
  • 3
  • 52
  • 93
  • Sorry to torture you more because I know this will likely eat at you until you get it to work too (I've been there). I wonder if you could get it to work with a `Expression>` too to make it work with Linq2Entities providers like Entity Framework. – Scott Chamberlain Aug 29 '13 at 13:55
  • 1
    @ScottChamberlain: I could probably do it with expressions, but I don't know if it would translate to compatible _runtime_ execution for entities (I suppose it _might_, after all, what's a few extra negations to an SQL query?). Maybe in my spare time I'll give it a shot. – Chris Sinclair Aug 29 '13 at 14:08
  • If you want to transform a lambda into its opposite, you can simply write, with variable `Expression> originalLambda`, `Expression> negatedLambda = originalLambda.Update(Expression.Not(originalLambda.Body), originalLambda.Parameters);` – Jean Hominal Aug 29 '13 at 15:10
  • @ScottChamberlain: I added a naive implementation with expressions. I tested against a local list, but not against Entity Framework. Feel free to give it a shot and let us know if it works! Jean Hominal, thanks for the sample code. – Chris Sinclair Aug 29 '13 at 15:35
  • Here's another idea that is much easier: Create a `Not` extension method. For instance: `public static Func Not(this Func pr) { return v => !pr(v); }`. Now you can do: `someList.Where(expr.Not())`, `someList.Where(expr.Not().Not())`, etc. – Steven Aug 29 '13 at 17:00
  • @Steven: That's a pretty great idea too! I don't know if I'd apply it in my answer here though as I _strictly_ wanted to achieve the `someList.Where(!expr)` syntax. Only major problem I see with it is that it flips the C# paradigm where the syntactical "nots" come first in the form of prefixed exclamation marks. We read the code as "not ", not as "expression not". (Although, it might read well for maybe some rebellious, rude code: "YouAreSoCool == true... NOT!") – Chris Sinclair Aug 29 '13 at 18:26
  • 2
    @ChrisSinclair: I do like your effort and like it when people do crazy trickery with the language. And I especially like it when this code is done in production, NOT!!! :P – Steven Aug 29 '13 at 20:32