2010-12-11 28 views
17

我正在尋找一種方法來否定用於過濾IQueryable序列的表達式。C#否定表達式

所以,我有這樣的:

Expression<Func<T, bool>> expression = (x => true); 

現在我想創建這將導致產生(x => false)表達 - 所以我基本上要否定expression

工作方法,我發現自己是這樣的:

var negatedExpression = 
    Expression.Lambda<Func<T, bool>> (Expression.Not(expression.Body), 
            expression.Parameters[0]))); 

但我幾乎可以肯定有一個更好的方式 - 你能幫助我嗎?(可能是Not(expression))。

回答

17

一個簡單的擴展方法:

public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> one) 
{ 
    var candidateExpr = one.Parameters[0]; 
    var body = Expression.Not(one.Body); 

    return Expression.Lambda<Func<T, bool>>(body, candidateExpr); 
} 

用法:

Expression<Func<int, bool>> condition = x => x > 5; 
var source = Enumerable.Range(1, 10); 
var result1 = source.Where(condition.Compile()); //6,7,8,9,10 
var result2 = source.Where(condition.Not().Compile()); //1,2,3,4,5 
+0

那麼,我知道如何包裝我的方式來否定一個'Not'方法的聲明,但我實際上是在尋求一種簡單的方法來實際執行否定*(它確實在我看來,調用'Expression.Lambda。 Blablabla'是一個巨大的矯枉過正)* – 2010-12-11 16:19:37

+2

表達式樹是不可變的,所以你必須創建一個新的lambda。 – 2010-12-11 16:31:49

-2

這是怎麼回事?

Expression<Func<bool>> expr =() => true; 
Expression<Func<bool>> negated =() => !expr.Compile()(); 
+0

您只是將輸入表達式轉換爲不透明的方法調用。這完全沒有幫助,因爲使用表達式的目的是提供的查詢可以理解它。 – CodesInChaos 2010-12-11 17:46:28

1

過帳以供將來參考。

丹尼陳的回答可以更通用:

public static Expression<TFunc> Not<TFunc>(this Expression<TFunc> baseExpr) 
{ 
    var param = baseExpr.Parameters; 
    var body = Expression.Not(baseExpr.Body); 
    var newExpr = Expression.Lambda<TFunc>(body, param); 
    return newExpr; 
} 

這個版本可以接收表達與任意數量的輸入參數。但它只增加了一點可用性,因爲表達式很可能會傳遞到像IEnumerable.Where這樣的函數。