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

somelist = somelist.Where(expr); 

これまでのところとても良いです。ラムダ式の<T, bool>を否定する

、コンパイルエラーになり
somelist = somelist.Where(!expr); 

Cannot apply ! operator to operand of type Func<T, bool>しかし、私はこのようなexprを否定したいと思います。

これに対して別の式変数を作成する必要がありますか?

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

を、次のような拡張メソッドを作成することができます。

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

今、あなたはこれを行うことができます:私はちょうど愚か答えとして存在し、これを捨てるつもりだ

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

。ちょうど明確にする:私はこれをしないだろう、と誰もこれを行うことをお勧めしません。 :)

somelist.Where(!expr)のような構文を得ることができたかどうかを知りたいと思っていました。

私は成功し、自分自身が嫌いです。

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

N.egatableがEDIT(ほんの少しの便利な構文ヘルパーだったと大幅に不要:私はは、明示的にMyClassを定義したり、何らかの形で隠されたオブジェクトラッパーのインスタンス化を行うことを避けるためにを望んでいたが、非常に得ることができませんでしたそこに、多分誰かが良いアイデアを持っているだろうと思った):

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)); 
    } 
} 
:本物の「魔法」が起こる場所

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

Negator<T>があります

最初に!演算子オーバーロードが関数の否定を実行すると(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 

だから、再び:

おそらく、非常に愚かなあなたは、このように前後にそれをひっくり返す保つことができるです。 :)確かにスティーブンの答えのように物事を行う適切な/元気な方法に固執する。

EDIT:シンタックスの使い方に関してまったく同じように動作する式を使用した実装です。それが「正しい」かどうかわからない、と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); 
    } 
} 
+0

申し訳ありませんが、私はあなたはそれがあまりにも動作するようになるまで、これはおそらくあなたに食べることを知っているので、(私がしてきましたそこ)。 Entity FrameworkのようなLinq2Entitiesプロバイダでも動作させるために、 'Expression > 'で動作させることができるのだろうかと思います。 –

+1

@ScottChamberlain:私はおそらく式でそれを行うことができますが、エンティティの互換性のある_runtime_実行に変換するかどうかはわかりません(おそらく_might_と思われますが、SQLクエリに対していくつかの否定がありますか?多分私の暇な時間に私はそれを撃つだろう。 –

+0

ラムダをその逆に変換したい場合は、変数 'Expression > originalLambda'、' Expression > negatedLambda = originalLambda.Update(Expression.Not(originalLambda.Body)、originalLambda .Parameters); ' –

関連する問題