78 votes

Le C# dispose-t-il de IsNullOrEmpty pour List/IEnumerable ?

Je sais qu'une liste vide est généralement préférable à NULL. Mais je vais retourner NULL, pour deux raisons principales

  1. Je dois vérifier et traiter les valeurs nulles de manière explicite, en évitant les bogues et les attaques.
  2. Il est facile de réaliser ?? pour obtenir une valeur de retour.

Pour les chaînes de caractères, nous avons IsNullOrEmpty. Y a-t-il quelque chose à partir du C# lui-même faire la même chose pour List ou IEnumerable ?

7 votes

Non, mais ajouter une méthode d'extension est trivial.

0 votes

82voto

Matthew Vines Points 14425

Rien n'est intégré dans le cadre, mais c'est une méthode d'extension assez directe.

Voir ici

/// <summary>
    /// Determines whether the collection is null or contains no elements.
    /// </summary>
    /// <typeparam name="T">The IEnumerable type.</typeparam>
    /// <param name="enumerable">The enumerable, which may be null or empty.</param>
    /// <returns>
    ///     <c>true</c> if the IEnumerable is null or empty; otherwise, <c>false</c>.
    /// </returns>
    public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
    {
        if (enumerable == null)
        {
            return true;
        }
        /* If this is a list, use the Count property for efficiency. 
         * The Count property is O(1) while IEnumerable.Count() is O(N). */
        var collection = enumerable as ICollection<T>;
        if (collection != null)
        {
            return collection.Count < 1;
        }
        return !enumerable.Any(); 
    }

Daniel Vaughan prend la peine d'effectuer un casting vers ICollection (lorsque cela est possible) pour des raisons de performance. C'est quelque chose que je n'aurais pas pensé à faire.

5 votes

Il convient toutefois de veiller à ce que l'appel à la fonction enumerable.Any() peut perdre un élément d'une énumération non révisable. Vous pouvez l'envelopper dans quelque chose qui gardera la trace de ce premier élément (et traitera les nullités de manière appropriée, bien sûr, ou nous annulons le problème entier du PO), mais il peut être plus pratique dans certains cas de fusionner avec une énumération vide et d'utiliser simplement le résultat.

0 votes

Euh, je suis bête ou la dernière ligne de cette fonction devrait être return !enumerable.Any(); ? Je vais le modifier.

1 votes

Doit-on aussi essayer de faire des castings vers des produits non génériques ICollection car un IEnumerable<Animal> pourrait être quelque chose comme une instance de List<Cat> qui ne met pas en œuvre ICollection<Animal> mais il met en œuvre un système non générique ICollection ?

60voto

Teodor Tite Points 857

Mise à jour tardive : depuis C# 6.0, le opérateur de propagation nulle peut être utilisé pour exprimer une concision comme celle-ci :

if (  list?.Count  > 0 ) // For List<T>
if ( array?.Length > 0 ) // For Array<T>

ou, en tant qu'alternative plus propre et plus générique pour les IEnumerable<T> :

if ( enumerable?.Any() ?? false )

Note 1 : toutes les variantes supérieures reflètent en fait IsNotNullOrEmpty contrairement à la question de l'OP ( citation ):

En raison de la préséance des opérateurs IsNullOrEmpty équivalents semblent moins attrayants :
if (!(list?.Count > 0))

Note 2 : ?? false est nécessaire, pour la raison suivante (résumé/citation de l'auteur) ce poste ):

?. L'opérateur retournera null si un membre enfant est null . Mais [...] si nous essayons d'obtenir un non Nullable membre, comme le Any() qui renvoie la méthode bool [...] le compilateur va "envelopper" une valeur de retour dans Nullable<> . Par exemple, Object?.Any() Est-ce que nous donner bool? (qui est Nullable<bool> ), pas bool . [...] Comme il ne peut pas être implicitement casté en bool cette expression ne peut pas être utilisée dans le if

Note 3 : en prime, la déclaration est également "thread-safe" (citation de la réponse de cette question ):

Dans un contexte multithread, si [ énumérable ] est accessible depuis un autre d'un autre thread (soit parce que c'est un champ accessible, soit parce qu'il est ou parce qu'il est fermé dans un lambda qui est exposé à un autre thread). pourrait être différente à chaque fois qu'elle est calculée [ c.-à-d. contrôle préalable de la nullité ]

27voto

Oded Points 271275

Il n'y a rien d'intégré.

Il s'agit pourtant d'une méthode d'extension simple :

public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
  if(enumerable == null)
    return true;

  return !enumerable.Any();
}

1 votes

Je me demande pourquoi cette réponse et la réponse acceptée ont toutes deux manqué le ! avant l'appel Any(). Ce même bug s'est propagé dans le code source de mon équipe.

11voto

Justin Niessner Points 144953
var nullOrEmpty = list == null || !list.Any();

4voto

Xipooo Points 558

Assembler les réponses précédentes en une méthode d'extension simple pour C# 6.0+ :

    public static bool IsNullOrEmpty<T>(this IEnumerable<T> me) => !me?.Any() ?? true;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X