2010-12-11 5 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

Ну, я действительно знаю, как обернуть свой путь, чтобы отрицать утверждение в методе «Не», но я действительно искал простой способ фактически выполнить отрицание * (мне кажется, что он вызывает выражение Expression.Lambda. Blablabla' - огромный перебор). * –

+2

Выражение Деревья неизменны, поэтому вам нужно создать новую лямбду. –

-2

Что относительно этого?

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

Вы просто превратили входное выражение в непрозрачный вызов метода. Это не помогает вообще, так как цель использования выражения заключается в том, что предоставленный запрос может его понять. – CodesInChaos

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.