Does C# have IsNullOrEmpty for List/IEnumerable?

87,758

Solution 1

nothing baked into the framework, but it's a pretty straight forward extension method.

See here

/// <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 takes the extra step of casting to ICollection (where possible) for performance reasons. Something I would not have thought to do.

Solution 2

Late update: since C# 6.0, the null-propagation operator may be used to express concise like this:

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

or, as a cleaner and more generic alternative for IEnumerable<T>:

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

Note 1: all upper variants reflect actually IsNotNullOrEmpty, in contrast to OP question (quote):

Because of operator precedence IsNullOrEmpty equivalents look less appealing:
if (!(list?.Count > 0))

Note 2: ?? false is necessary, because of the following reason (summary/quote from this post):

?. operator will return null if a child member is null. But [...] if we try to get a non-Nullable member, like the Any() method, that returns bool [...] the compiler will "wrap" a return value in Nullable<>. For example, Object?.Any() will give us bool? (which is Nullable<bool>), not bool. [...] Since it can't be implicitly casted to bool this expression cannot be used in the if

Note 3: as a bonus, the statement is also "thread-safe" (quote from answer of this question):

In a multithreaded context, if [enumerable] is accessible from another thread (either because it's a field that's accessible or because it's closed over in a lambda that is exposed to another thread) then the value could be different each time it's computed [i.e.prior null-check]

Solution 3

There is nothing built in.

It is a simple extension method though:

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

  return !enumerable.Any();
}

Solution 4

var nullOrEmpty = list == null || !list.Any();

Solution 5

Putting together the previous answers into a simple extension method for C# 6.0+:

    public static bool IsNullOrEmpty<T>(this IEnumerable<T> me) => !me?.Any() ?? true;
Share:
87,758
Eric Yin
Author by

Eric Yin

Updated on July 12, 2022

Comments

  • Eric Yin
    Eric Yin almost 2 years

    I know generally empty List is more prefer than NULL. But I am going to return NULL, for mainly two reasons

    1. I have to check and handle null values explicitly, avoiding bugs and attacks.
    2. It is easy to perform ?? operation afterwards to get a return value.

    For strings, we have IsNullOrEmpty. Is there anything from C# itself doing the same thing for List or IEnumerable?

  • Jon Hanna
    Jon Hanna over 12 years
    Caution must be taken though that the call to enumerable.Any() can lose an element of a non-rewindable enumeration. You can wrap it in something that'll keep track of that first element (and handle null nicely of course or we negate the OP's whole issue), but it can be handier in some cases to coalesce with an empty enumeration and just use the result.
  • Patrick Szalapski
    Patrick Szalapski almost 12 years
    Uh, am I daft or should the last line of that function be return !enumerable.Any(); ? I'll edit it.
  • supercat
    supercat almost 12 years
    Should one also try casting to non-generic ICollection, since an IEnumerable<Animal> might be something like an instance of List<Cat>, which does not implement ICollection<Animal> but does implement non-generic ICollection?
  • Ruutert
    Ruutert over 11 years
    This doesn't work for XmlNodeList? XmlNodeList is also implementing the IEnumerable interface, why doesn't work this?
  • AaronLS
    AaronLS over 10 years
    Could you give me an example of a non-rewindable collection in .NET? I mean just name of an existing class in the framework, not asking you to give me an example implementation of one.
  • Jon Hanna
    Jon Hanna over 10 years
    @AaronLS the result of most Linq queries.
  • AaronLS
    AaronLS over 10 years
    What would be the concrete type in that case? I'm aware of IQueryable which isn't really a list until you try to ToList/foreach at which point it materialized. I imagine there is some intermediate concrete type for IQueryable that is a forward only data reader under the hood, so what you say makes sense, I just can't imagine where you'd actually encounter this problem. If you foreach(var item in someQueryable) would generate its own eneumerator, and then did someQueryable.Any() would be a seperate query and wouldn't affect the current foreach enumerator AFAIK.
  • AaronLS
    AaronLS over 10 years
    Not challenging you, just trying to explain my confusion.
  • Jon Hanna
    Jon Hanna over 10 years
    @AaronLS it would be a separate enumerator, which would require you to run the query again, which is bad enough. If it was cast to IEnumerable then even more so, as the query will have been lost.
  • xmoex
    xmoex about 10 years
    as seen here: msdn.microsoft.com/en-us/library/bb337697%28v=vs.110%29.aspx (check remarks) "The enumeration of source is stopped as soon as the result can be determined." wich makes me think a cast to collection is unnecessary as enumerable.Any() should have O(1) as well. so why cast to a list if you don't really know it is a list?
  • Lee Grissom
    Lee Grissom over 9 years
    The comment about "IEnumerable.Count() is O(N)" is correct... but the code isn't doing that, it's calling Any(). Although it's still a good idea to cast so that you can avoid the GetEnumerator and MoveNext code under the hood when calling Any.
  • stannius
    stannius about 8 years
    I wonder why both this and the accepted answer both missed the ! before the Any() call. That same bug got propagated into my team's source code.
  • PRMan
    PRMan about 8 years
    This could now be written in one line: return a == null || ((a as ICollection)?.Count == 0) || !a.Any();
  • MikeT
    MikeT over 7 years
    Code only answers are not good answers, try adding a few lines explaining what the problem was and how your code fixes it
  • tytyryty
    tytyryty over 7 years
    Casting to ICollection is correct and good practice in general. All Linq methods implementations use casting to optimize performance. However, in this case, it is not necessary at all, as Any method internally will just call MoveNext only once.
  • Lee Grissom
    Lee Grissom over 7 years
    This won't compile if list is IEnumerable.
  • Lee Grissom
    Lee Grissom over 7 years
    I just realized that this solution omits a short-circuit for IReadOnlyCollection (which does not inherit from ICollection).
  • Teodor Tite
    Teodor Tite over 7 years
    @GrimR3 Yes, you're right: that's more strait to the question. I've written it like that to be inline with the quote/referece.
  • El Mac
    El Mac almost 6 years
    Stupid out-of-topic-question: Why is ICollection.Count O(1) and IEnumerable.Count() O(n)? I undestand the latter one, but why is a simple cast enough to make it O(1)?
  • Admin
    Admin almost 5 years
    @ElMac The spec of ICollection.Count is that the count is tracked, any implementation should return the count without iterating the values to calculate it on demand. But as another person said in comments, the same optimisation should also be called for IReadOnlyCollection. Also, LINQ.Any uses the optimisation on ICollection, but not on IReadOnlyCollection.
  • intrepidis
    intrepidis over 4 years
    You can check for 0 or 1 elements with this: (myArray?.Length ?? 0) < 2