C# 取反一个表达式

27
我希望找到一种方法来否定用于筛选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个回答

27
一个简单的扩展方法:
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

我知道如何通过“Not”方法将语句否定,但我实际上正在寻找一种简单的方法来执行否定(对我来说,调用Expression.Lambda.Blablabla似乎过于繁琐)。 - Yippie-Ki-Yay
2
表达式树是不可变的,因此您必须创建一个新的lambda。 - Jb Evain

3

为将来参考而发布。

Danny Chen的回答可以更加通用:

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 这样的函数。


0
我个人不喜欢这种作为扩展方法的方式,因为它读起来“不对”。我结合了@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);

-5

这个怎么样?

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

你刚刚将输入表达式转换为一个不透明的方法调用。这样做没有任何帮助,因为使用表达式的目的是让提供的查询能够理解它。 - CodesInChaos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接