C# отрицает выражение

Я ищу способ отменить выражение, используемое для фильтрации IQueryable последовательности.

Итак, у меня есть что-то вроде:

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), наверное).

4 ответа

Решение

Простой метод расширения:

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

Размещение для дальнейшего использования.

Ответ Дэнни Чена можно сделать более общим:

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 тем не мение.

Лично мне это не нравится как метод расширения, потому что он читается «неправильно». Я объединил ответы @Cheng Chen и @Nathan и немного модернизировал их:

      public static class ExpressionUtils
{
    public static Expression<Func<T, bool>> Not<T>(Expression<Func<T, bool>> predicate) =>
        Expression.Lambda<Func<T, bool>>(Expression.Not(predicate.Body), predicate.Parameters);
}

Использование (Entity Framework):

      Expression<Func<Employee, bool>> isOld = a => a.Age > 40;
var isYoung = ExpressionUtils.Not<Employee>(isOld);

var juniors = await dbContext.Employees.Where(isYoung).ToListAsync(cancellationToken);

Как насчет этого?

Expression<Func<bool>> expr = () => true;
Expression<Func<bool>> negated = () => !expr.Compile()();
Другие вопросы по тегам