C#否定了一个表达式

时间:2010-12-11 15:36:02

标签: c# expression negate

我正在寻找一种方法来否定用于过滤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)之类的东西)。

3 个答案:

答案 0 :(得分:18)

一种简单的扩展方法:

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

答案 1 :(得分:1)

发布以供将来参考。

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

use threads;

use Thread::Queue qw( );  # 3.01+

use constant NUM_WORKERS => 4;

sub worker {
    my $num = shift;
    say "Job $num Started\n";
    system("sleep_for_10_sec.bash");  # Make sure starts with #! and is executable.
    say "Job $num Finished\n";
}

{
   my $q = Thread::Queue->new();

   for (1..NUM_WORKERS) {
      while (defined( my $job = $q->dequeue() )) {
         worker($job);
      }
   }    

   $q->enqueue(1..4, 1..4);

   $q->end();
   $_->join() for threads->list;
}

此版本可以接收包含任意数量输入参数的Expression。但是,它只增加了一点可用性,因为表达式很可能会传递给像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; } 这样的函数。

答案 2 :(得分:-3)

这个怎么样?

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