【问题标题】:Is there any way to negate a Predicate?有没有办法否定谓词?
【发布时间】:2010-01-30 02:32:44
【问题描述】:

我想做这样的事情:

List<SomeClass> list1 = ...
List<SomeClass> list2 = ...
Predicate<SomeClass> condition = ...

...

list2.RemoveAll (!condition);

...

list2.AddRange (list1.FindAll (condition));

但是,这会导致编译器错误,因为 ! 不能应用于 Predicate&lt;SomeClass&gt;。有没有办法做到这一点?

【问题讨论】:

    标签: c# .net linq predicate


    【解决方案1】:

    您可以使用 lambda 表达式就地定义一个匿名委托,该委托是否定谓词结果的结果:

    list.RemoveAll(x => !condition(x));    
    

    另一种选择:

    static Predicate<T> Negate<T>(Predicate<T> predicate) {
         return x => !predicate(x);
    }
    

    用法:

    // list is List<T> some T
    // predicate is Predicate<T> some T
    list.RemoveAll(Negate(predicate));
    

    list.RemoveAll(!condition) 不起作用的原因是没有在委托上定义 ! 运算符。这就是为什么您必须按照上面的condition 定义一个新的委托。

    【讨论】:

      【解决方案2】:

      这实际上是可能的,但可能与您习惯的形式略有不同。在 .NET 中,lambda 表达式可以被解释为委托expression trees。在表达式树上执行NOT 操作相对简单。

      这是一个使用您的代码作为起点的示例:

      namespace Sample
      {
          using System;
          using System.Collections.Generic;
          using System.Linq.Expressions;
      
          internal class ExpressionSample
          {
              private static Expression<TDelegate> Negate<TDelegate>(Expression<TDelegate> expression)
              {
                  return Expression.Lambda<TDelegate>(Expression.Not(expression.Body), expression.Parameters);
              }
      
              private static void Main()
              {
                  // Match any string of length 2 or more characters
                  Expression<Predicate<string>> expression = (s) => s.Length > 1;
      
                  // Logical negation, i.e. match string of length 1 or fewer characters
                  Expression<Predicate<string>> negatedExpression = ExpressionSample.Negate(expression);
      
                  // Compile expressions to predicates
                  Predicate<string> predicate = expression.Compile();
                  Predicate<string> negativePredicate = negatedExpression.Compile();
      
                  List<string> list1 = new List<string> { string.Empty, "an item", "x", "another item" };
                  List<string> list2 = new List<string> { "yet another item", "still another item", "y", string.Empty };
      
                  list2.RemoveAll(negativePredicate);
                  list2.AddRange(list1.FindAll(predicate));
      
                  list2.ForEach((s) => Console.WriteLine(s));
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2019-07-02
        • 2021-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-22
        相关资源
        最近更新 更多