2010-01-30 17 views
22

voglio fare qualcosa di simile:C'è un modo per negare un predicato?

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

... 

list2.RemoveAll (!condition); 

... 

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

Tuttavia, questo si traduce in un errore di compilazione, come ! non può essere applicato a Predicate<SomeClass>. C'è un modo per fare questo?

risposta

29

Si potrebbe usare un'espressione lambda per definire un inplace delegato anonima che è il risultato di negare il risultato del predicato:

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

Un'altra opzione:

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)); 

Il motivo per cui lo list.RemoveAll(!condition) non funziona è che non vi è nessun operatore ! definito sui delegati. Questo è il motivo per cui è necessario definire un nuovo delegato in termini di condition come mostrato sopra.

8

Questo è effettivamente possibile, ma forse in una forma leggermente diversa da quella a cui sei abituato. In .NET, le espressioni lambda possono essere interpretate come delegati o come expression trees. È relativamente semplice eseguire un'operazione NOT su un albero di espressioni.

Ecco un esempio utilizzando il codice come punto di partenza:

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)); 
     } 
    } 
} 
Problemi correlati