web-dev-qa-db-fra.com

Est-ce que C # a IsNullOrEmpty pour List/IEnumerable?

Je sais que la liste généralement vide est plus préférable que NULL. Mais je vais retourner NULL, principalement pour deux raisons

  1. Je dois vérifier et gérer les valeurs null explicitement, en évitant les bugs et les attaques.
  2. Il est facile d'effectuer l'opération ?? par la suite pour obtenir une valeur de retour.

Pour les chaînes, nous avons IsNullOrEmpty. Y at-il quelque chose de C # lui-même faire la même chose pour List ou IEnumerable?

60
Eric Yin

rien dans le cadre, mais c'est une méthode d'extension assez simple.

Vois 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 fait un pas de plus vers le casting chez ICollection (si possible) pour des raisons de performances. Quelque chose que je n'aurais pas pensé faire.

65
Matthew Vines

Late update: depuis C # 6.0, le opérateur de propagation nul peut être utilisé pour exprimer de manière concise comme ceci:

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

Note 1:?? false est nécessaire pour la raison suivante (résumé/citation de cet article ):

?. L'opérateur retournera null si un membre enfant est null. Mais si [...] nous essayons d'obtenir un membre non -Nullable, comme le La méthode Any(), qui retourne bool [...] le compilateur aura "encapsuler" une valeur de retour dans Nullable<>. Par exemple, Object?.Any() will donnez-nous bool? (qui est Nullable<bool>), pas bool. [...] Puisqu'elle ne peut pas être implicitement convertie en bool, cette expression ne peut pas être utilisée dans la if

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

Dans un contexte multithread, si [enumerable] est accessible à partir d'un autre thread (soit parce que c'est un champ accessible, soit parce que fermé dans un lambda exposé à un autre thread), puis le la valeur peut être différente chaque fois qu'il est calculé [i.e.prior null-check} _]

35
Teodor Tite

Il n'y a rien intégré.

C'est une méthode d'extension simple cependant:

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

  return !enumerable.Any();
}
23
Oded
var nullOrEmpty = list == null || !list.Any();
9
Justin Niessner

Rassembler 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;
1
Xipooo

Comme tout le monde l’a dit, rien n’est intégré dans le cadre, mais si vous utilisez Castle, Castle.Core.Internal l’a.

using Castle.Core.Internal;

namespace PhoneNumbers
{
    public class PhoneNumberService : IPhoneNumberService
    {
        public void ConsolidateNumbers(Account accountRequest)
        {
            if (accountRequest.Addresses.IsNullOrEmpty()) // Addresses is List<T>
            {
                return;
            }
            ...
1
Matt Frear

Si vous devez pouvoir extraire tous les éléments s'il n'est pas vide, certaines des réponses fournies ne fonctionneront pas car l'appel à Any() sur un énumérable non réenroulable "oubliera" un élément.

Vous pouvez adopter une approche différente et transformer les valeurs nulles en vides:

bool didSomething = false;
foreach(var element in someEnumeration ?? Enumerable.Empty<MyType>())
{
  //some sensible thing to do on element...
  didSomething = true;
}
if(!didSomething)
{
  //handle the fact that it was null or empty (without caring which).
}

De même, (someEnumeration ?? Enumerable.Empty<MyType>()).ToList() etc. peuvent être utilisés.

1
Jon Hanna
var nullOrEmpty = !( list?.Count > 0 );
0
eddy white

pour moi, la meilleure méthode isNullOrEmpty ressemble à ceci

public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
    return !enumerable?.Any() ?? true;
}
0
keipa

J'ai modifié la suggestion de Matthew Vines pour éviter le "problème de dénombrement multiple possible de IEnumerable" - problème . (Voir aussi le commentaire de Jon Hanna) 

public static bool IsNullOrEmpty(this IEnumerable items)
    => items == null
    || (items as ICollection)?.Count == 0
    || !items.GetEnumerator().MoveNext();

... et le test unitaire:

[Test]
public void TestEnumerableEx()
{
    List<int> list = null;
    Assert.IsTrue(list.IsNullOrEmpty());

    list = new List<int>();
    Assert.IsTrue(list.IsNullOrEmpty());

    list.AddRange(new []{1, 2, 3});
    Assert.IsFalse(list.IsNullOrEmpty());

    var enumerator = list.GetEnumerator();
    for(var i = 1; i <= list.Count; i++)
    {
        Assert.IsFalse(list.IsNullOrEmpty());
        Assert.IsTrue(enumerator.MoveNext());
        Assert.AreEqual(i, enumerator.Current);
    }

    Assert.IsFalse(list.IsNullOrEmpty());
    Assert.IsFalse(enumerator.MoveNext());
}
0
Georg