Is there any way to negate a Predicate?

后端 未结 2 737
野性不改
野性不改 2020-12-18 17:52

I want to do something like this:

List list1 = ...
List list2 = ...
Predicate condition = ...

...

list2.         


        
相关标签:
2条回答
  • This is actually possible, but maybe in a slightly different form than you're used to. In .NET, lambda expressions can either be interpreted as delegates OR as expression trees. It is relatively straightforward to perform a NOT operation on an expression tree.

    Here is a sample using your code as a starting point:

    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));
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-18 18:38

    You could use a lambda expression to define an anonymous delegate inplace that is the result of negating the result of the predicate:

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

    Another option:

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

    Usage:

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

    The reason that list.RemoveAll(!condition) does not work is that there is no ! operator defined on delegates. This is why you must define a new delegate in terms of condition as shown above.

    0 讨论(0)
提交回复
热议问题