2011-09-06 4 views
2

J'ai besoin d'un peu d'aide pour simplifier une requête LINQ. Les conditions sont les suivantes:Simplifier la requête LINQ

  • J'ai besoin d'appliquer bool IsValid(string expression) à chaque élément d'une séquence donnée.
  • Si IsValid est vrai pour tous les éléments, renvoyez true.
  • Si IsValid est false pour un élément, renvoyez false. Si la séquence est nulle ou vide, renvoyer également false.

La requête que je suis venu avec est

try 
{ 
    (sequence.DefaultIfEmpty().Where(item => !IsValid(item).Count() == 0) 
} 
catch (ArgumentNullException) 
{ 
    return false; 
} 

Le point est que IsValid(null) jette un ArgumentNullException qui est interceptée par le bloc catch. Cependant, je pense que c'est trop compliqué. Y a-t-il un moyen de simplifier la méthode sans compter sur ce fait?

Répondre

6

pourquoi pas:

return sequence.Any() && sequence.All(item => IsValid(item)); 

Si vous êtes inquiet au sujet de la vérification sequence.Any() distincte qui se traduit par un avertissement ReSharper (qui est garanti avec une séquence que vous ne pouvez itérer une fois comme un réseau, etc. DB), vous pouvez écrire une méthode d'extension générique qui effectue la vérification et la séquence itère une seule fois:

public static bool NotEmptyAndValid<T>(this IEnumerable<T> source, 
             Func<T, bool> predicate) 
{ 
    bool hasItem = false; 
    foreach(var item in source) 
    { 
     hasItem = true; 
     if(!predicate(item)) 
      return false; 
    } 
    return hasItem; 
} 

Ensuite, vous pouvez le faire simplement:

return sequence.NotEmptyAndValid(x => IsValid(x)); 
+0

Oui, vous avez raison! Cependant, cela déclenche l'avertissement "Énumération multiple possible de IEnumerable" de ReSharper, que je veux éviter. – User

+0

DefaultIfEmpty retournera simplement un élément nul - quel est son but ici? –

+0

oui juste fixait cette partie, n'a pas vu l'exigence pour la collecte vide – BrokenGlass

3

Vous devriez pouvoir utiliser:

return sequence.Any() && sequence.All(item => IsValid(item)); 
+0

Oui, vous avez raison! Cependant, cela déclenche l'avertissement "Énumération multiple possible de IEnumerable" de ReSharper, que je veux éviter. – User

+0

@User: Dans ce cas, pour obtenir votre enregistrement null/vide correctement, une boucle pourrait être la meilleure option ... –

+0

Cela ressemble à une réponse simultanée à moi. –

1

Je ne suis pas sûr que ça va être facile de le faire bien avec juste une seule passe. Je suis sûr que c'est faisable, mais je ne suis pas sûr que ce serait bien. Cependant, il est mort facile d'écrire votre propre méthode d'extension:

(EDIT:.. Je vois BrokenGlass a écrit une méthode similaire avec foreach Je vais laisser cela comme une alternative)

public static boolean AllAndNotEmpty<T>(this IEnumerable<T> source, 
             Func<T, bool> predicate) 
{ 
    if (source == null) 
    { 
     throw new ArgumentNullException("source"); 
    } 
    if (predicate == null) 
    { 
     throw new ArgumentNullException("predicate"); 
    } 
    using (var iterator = source.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      return false; 
     } 
     do 
     { 
      if (!predicate(iterator.Current)) 
      { 
       return false; 
      } 
     } while (iterator.MoveNext());    
    } 
    return true; 
} 

Puis:

var result = items.AllAndNotEmpty(IsValid); 
Questions connexes