76

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?

duplode
  • 33,731
  • 7
  • 79
  • 150
Eric Yin
  • 8,737
  • 19
  • 77
  • 118

12 Answers12

82

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.

Tom
  • 105
  • 8
Matthew Vines
  • 27,253
  • 7
  • 76
  • 97
  • 5
    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. – Jon Hanna Dec 20 '11 at 23:40
  • Uh, am I daft or should the last line of that function be `return !enumerable.Any();` ? I'll edit it. – Patrick Szalapski Aug 02 '12 at 20:32
  • 1
    Should one also try casting to non-generic `ICollection`, since an `IEnumerable` might be something like an instance of `List`, which does not implement `ICollection` but does implement non-generic `ICollection`? – supercat Aug 03 '12 at 19:37
  • This doesn't work for XmlNodeList? XmlNodeList is also implementing the IEnumerable interface, why doesn't work this? – Ruutert Oct 30 '12 at 09:51
  • 7
    as seen here: http://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? – xmoex Mar 31 '14 at 07:33
  • 1
    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`. – Lee Grissom Nov 08 '14 at 05:41
  • 3
    This could now be written in one line: return a == null || ((a as ICollection)?.Count == 0) || !a.Any(); – PRMan May 07 '16 at 14:31
  • 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. – tytyryty Jan 15 '17 at 10:29
  • 1
    I just realized that this solution omits a short-circuit for `IReadOnlyCollection` (which does _not_ inherit from ICollection). – Lee Grissom Jan 19 '17 at 04:23
  • 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)? – El Mac Jul 10 '18 at 07:03
  • 2
    @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. –  Sep 18 '19 at 18:09
59

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]

Teodor Tite
  • 1,855
  • 3
  • 24
  • 31
27

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();
}
David Peden
  • 17,596
  • 6
  • 52
  • 72
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 1
    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. – stannius Apr 18 '16 at 17:25
10
var nullOrEmpty = list == null || !list.Any();
Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
4

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;
Xipooo
  • 1,496
  • 1
  • 14
  • 13
2

As everyone else has said, nothing is built into the framework, but if you are using Castle then Castle.Core.Internal has it.

using Castle.Core.Internal;

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

If you need to be able to retrieve all of the elements in the case of it not being empty, then some of the answers here won't work, because the call to Any() on a non-rewindable enumerable will "forget" an element.

You could take a different approach and turn nulls into empties:

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).
}

Likewise (someEnumeration ?? Enumerable.Empty<MyType>()).ToList() etc. can be used.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • 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. – AaronLS Oct 21 '13 at 19:52
  • @AaronLS the result of most Linq queries. – Jon Hanna Oct 21 '13 at 20:25
  • 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 Oct 21 '13 at 21:52
  • Not challenging you, just trying to explain my confusion. – AaronLS Oct 21 '13 at 21:53
  • @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. – Jon Hanna Oct 21 '13 at 22:43
0

I modified the suggestion from Matthew Vines to avoid the "Possible multiple enumeration of IEnumerable" - problem. (see also the comment from Jon Hanna)

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

... and the unit test:

[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());
}
Georg
  • 1,946
  • 26
  • 18
0
var nullOrEmpty = !( list?.Count > 0 );
eddy white
  • 301
  • 2
  • 24
0

for me best isNullOrEmpty method is looked like this

public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
    return !enumerable?.Any() ?? true;
}
keipa
  • 702
  • 1
  • 8
  • 17
0
 public static class IEnumerableExtention
 {
     public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
     {
         if (enumerable == null)
         {
             return true;
         }
 
         using var enumerator = enumerable.GetEnumerator();
 
         var isEmpty = !enumerator.MoveNext();
 
         return isEmpty;
     }
 }
0

One-line with nullable support:

public static bool IsNullOrEmpty<T>(this IEnumerable<T>? enumerable) => 
            enumerable == null || !enumerable.Any();
M.Hassan
  • 10,282
  • 5
  • 65
  • 84