ChatGPT解决这个技术问题 Extra ChatGPT

How to check if IEnumerable is null or empty?

I love string.IsNullOrEmpty method. I'd love to have something that would allow the same functionality for IEnumerable. Is there such? Maybe some collection helper class? The reason I am asking is that in if statements the code looks cluttered if the patter is (mylist != null && mylist.Any()). It would be much cleaner to have Foo.IsAny(myList).

This post doesn't give that answer: IEnumerable is empty?.

@msarchet: I'd probably give you the answer if this weren't the comment :)
to me this seems like kind of an XY problem. instead of asking "how can I check for null exactly everywhere without it being so bothersome" you should ask "how can I improve my design so I won't HAVE to check for null everywhere?"
You can use the following line instead: myCollection?.FirstOrDefault() == null

M
Marc Gravell

Sure you could write that:

public static class Utils {
    public static bool IsAny<T>(this IEnumerable<T> data) {
        return data != null && data.Any();
    }
}

however, be cautious that not all sequences are repeatable; generally I prefer to only walk them once, just in case.


Is this a good pattern? I would drop the this there – I consider extension methods which are assumed to be called on null as a sign of ugly design.
@Mormegil Why? extension methods finally give C# some capability to work with nulls, which other languages (like Ruby) completely take for granted.
Why is this necessarily bad? As in this case, it is sometimes very handy since it lets you treat things more homogeneously and with fewer special cases.
@Mormegil meh - I can't get excited about that. As long as the intent is clear, etc.
@Miryafa .Any() is an extension method that operates on IEnumerable<T> (or IQueryable<T>, although that's a different scenario). Doing so consumes the sequence, at least partially (although that still means it is consumed) - it might only need to read one element (especially if there is no predicate). As such, since sequences (IEnumerable<T>) do not need to be repeatable, that might be it. Any() without a predicate is essentially equivalent to foreach(var x in sequence) { return true; } return false; - although it uses GetEnumerator() etc instead of compiler syntax
M
Matt Greer
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable) {
    return enumerable == null || !enumerable.Any();
}

well, not quite, the OP asked for IEnumerable, not IEnumerable ;-)
Yes, IEnumerable has no Any() extension.
Add System.Linq to enable Any() extension
y
yoyo

Here's a modified version of @Matt Greer's useful answer that includes a static wrapper class so you can just copy-paste this into a new source file, doesn't depend on Linq, and adds a generic IEnumerable<T> overload, to avoid the boxing of value types that would occur with the non-generic version. [EDIT: Note that use of IEnumerable<T> does not prevent boxing of the enumerator, duck-typing can't prevent that, but at least the elements in a value-typed collection will not each be boxed.]

using System.Collections;
using System.Collections.Generic;

public static class IsNullOrEmptyExtension
{
    public static bool IsNullOrEmpty(this IEnumerable source)
    {
        if (source != null)
        {
            foreach (object obj in source)
            {
                return false;
            }
        }
        return true;
    }

    public static bool IsNullOrEmpty<T>(this IEnumerable<T> source)
    {
        if (source != null)
        {
            foreach (T obj in source)
            {
                return false;
            }
        }
        return true;
    }
}

D
Darren

Another way would be to get the Enumerator and call the MoveNext() method to see if there are any items:

if (mylist != null && mylist.GetEnumerator().MoveNext())
{
    // The list is not null or empty
}

This works for IEnumerable as well as IEnumerable.


Should you call dispose on this enumerator? If the collection is multithreading aware? Yes. stackoverflow.com/questions/13459447/…
@TamusJRoyce Note that your statement is only true for IEnumerable<T>, as non-generic IEnumerable doesn't implement IDisposable.
R
Ronald Rey

The way I do it, taking advantage of some modern C# features:

Option 1)

public static class Utils {
    public static bool IsNullOrEmpty<T>(this IEnumerable<T> list) {
        return !(list?.Any() ?? false);
    }
}

Option 2)

public static class Utils {
    public static bool IsNullOrEmpty<T>(this IEnumerable<T> list) {
        return !(list?.Any()).GetValueOrDefault();
    }
}

And by the way, never use Count == 0 or Count() == 0 just to check if a collection is empty. Always use Linq's .Any()


Count == 0 is just fine.... Maybe faster than Any()? However you are correct on the Count() == 0 being bad. For those that are wondering Count() iterates through your entire collection, so if it's huge could add a ton of overhead!
Count() only iterates the enumeration if it can't be cast to an ICollection. In other words, when you call this method, if there's already a Count property on the object, it will just return that and the performance should be identical. Check out the implementation here: referencesource.microsoft.com/#System.Core/System/Linq/…
If you are working with an IEnumerable, using Count() to test for emptyness is definitely a bad idea since the Linq implementation WILL iterate over the entire collection, while Any will just move the iterator once. Keep in mind that you can't use the Count property in this case since it's not part of the IEnumerable interface. That's why is always a better idea to just use Any() to test for emptyness in all scenarios, in my opinion.
Nice example of how not-readable negation operator ! can be, specially in the second option ;)
S
Scholtz
if (collection?.Any() == true){
    // if collection contains more than one item
}
if (collection?.Any() != true){
    // if collection is null
    // if collection does not contain any item
}

T
Thomas Mulder

Starting with C#6 you can use null propagation: myList?.Any() == true

If you still find this too cloggy or prefer a good ol' extension method, I would recommend Matt Greer and Marc Gravell's answers, yet with a bit of extended functionality for completeness.

Their answers provide the same basic functionality, but each from another perspective. Matt's answer uses the string.IsNullOrEmpty-mentality, whereas Marc's answer takes Linq's .Any() road to get the job done.

I am personally inclined to use the .Any() road, but would like to add the condition checking functionality from the method's other overload:

    public static bool AnyNotNull<T>(this IEnumerable<T> source, Func<T, bool> predicate = null)
    {
        if (source == null) return false;
        return predicate == null
            ? source.Any()
            : source.Any(predicate);
    }

So you can still do things like : myList.AnyNotNull(item=>item.AnswerToLife == 42); as you could with the regular .Any() but with the added null check

Note that with the C#6 way: myList?.Any() returns a bool? rather than a bool, which is the actual effect of propagating null


The problem with collection?.Any() is that is not transitive. When null, collection?.Any() == true is false, but collection?.Any() == false is also false. Moreover, !collection?.Any() == false is false too...
H
Hossein Narimani Rad

This may help

public static bool IsAny<T>(this IEnumerable<T> enumerable)
{
    return enumerable?.Any() == true;
}

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

J
Just Fair

Jon Skeet's anwser (https://stackoverflow.com/a/28904021/8207463) has a good approach using Extension Method - Any() for NULL and EMPTY. BUT he´s validating the questions´owner in case for NOT NULL. So carefully change Jon´s approach to validate AS NULL to:

If (yourList?.Any() != true) 
{
     ..your code...
}

DO NOT use ( will not validate AS NULL):

If (yourList?.Any() == false) 
{
     ..your code...
}

You can also in case validating AS NOT NULL ( NOT tested just as example but without compiler error) do something like using predicate :

If (yourList?.Any(p => p.anyItem == null) == true) 
{
     ..your code...
}

https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,8788153112b7ffd0

For which .NET version you can use it please check:

https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.any?view=netframework-4.8#moniker-applies-to


C
Community

Here's the code from Marc Gravell's answer, along with an example of using it.

using System;
using System.Collections.Generic;
using System.Linq;

public static class Utils
{
    public static bool IsAny<T>(this IEnumerable<T> data)
    {
        return data != null && data.Any();
    }
}

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<string> items;
        //items = null;
        //items = new String[0];
        items = new String[] { "foo", "bar", "baz" };

        /*** Example Starts Here ***/
        if (items.IsAny())
        {
            foreach (var item in items)
            {
                Console.WriteLine(item);
            }
        }
        else
        {
            Console.WriteLine("No items.");
        }
    }
}

As he says, not all sequences are repeatable, so that code may sometimes cause problems, because IsAny() starts stepping through the sequence. I suspect what Robert Harvey's answer meant was that you often don't need to check for null and empty. Often, you can just check for null and then use foreach.

To avoid starting the sequence twice and take advantage of foreach, I just wrote some code like this:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<string> items;
        //items = null;
        //items = new String[0];
        items = new String[] { "foo", "bar", "baz" };

        /*** Example Starts Here ***/
        bool isEmpty = true;
        if (items != null)
        {
            foreach (var item in items)
            {
                isEmpty = false;
                Console.WriteLine(item);
            }
        }
        if (isEmpty)
        {
            Console.WriteLine("No items.");
        }
    }
}

I guess the extension method saves you a couple of lines of typing, but this code seems clearer to me. I suspect that some developers wouldn't immediately realize that IsAny(items) will actually start stepping through the sequence. (Of course if you're using a lot of sequences, you quickly learn to think about what steps through them.)


If you call IsAny on a null, it will throw an exception
Did you try it, @Ace? It looks like it would throw an exception, but extension methods can be called on null instances.
S
Sabyasachi Mukherjee

I use Bool IsCollectionNullOrEmpty = !(Collection?.Any()??false);. Hope this helps.

Breakdown:

Collection?.Any() will return null if Collection is null, and false if Collection is empty.

Collection?.Any()??false will give us false if Collection is empty, and false if Collection is null.

Complement of that will give us IsEmptyOrNull.


A
Adel Tabareh

One can use this line for that verification when it's about reference (nullable) types and when no null item expected among the items

myCollection?.FirstOrDefault() == null

H
Hosein Djadidi

I had the same problem and I solve it like :

    public bool HasMember(IEnumerable<TEntity> Dataset)
    {
        return Dataset != null && Dataset.Any(c=>c!=null);
    }

"c=>c!=null" will ignore all the null entities.


K
Keith Banner

I built this off of the answer by @Matt Greer

He answered the OP's question perfectly.

I wanted something like this while maintaining the original capabilities of Any while also checking for null. I'm posting this in case anyone else needs something similar.

Specifically I wanted to still be able to pass in a predicate.

public static class Utilities
{
    /// <summary>
    /// Determines whether a sequence has a value and contains any elements.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="source">The <see cref="System.Collections.Generic.IEnumerable"/> to check for emptiness.</param>
    /// <returns>true if the source sequence is not null and contains any elements; otherwise, false.</returns>
    public static bool AnyNotNull<TSource>(this IEnumerable<TSource> source)
    {
        return source?.Any() == true;
    }

    /// <summary>
    /// Determines whether a sequence has a value and any element of a sequence satisfies a condition.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="source">An <see cref="System.Collections.Generic.IEnumerable"/> whose elements to apply the predicate to.</param>
    /// <param name="predicate">A function to test each element for a condition.</param>
    /// <returns>true if the source sequence is not null and any elements in the source sequence pass the test in the specified predicate; otherwise, false.</returns>
    public static bool AnyNotNull<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
    {
        return source?.Any(predicate) == true;
    }
}

The naming of the extension method could probably be better.


B
Basheer AL-MOMANI

I used simple if to check for it

check out my solution

foreach (Pet pet in v.Pets)
{
    if (pet == null)
    {
        Console.WriteLine(" No pet");// enumerator is empty
        break;
    }
    Console.WriteLine("  {0}", pet.Name);
}

S
Shakeer Hussain

The other best solution as below to check empty or not ?

for(var item in listEnumerable)
{
 var count=item.Length;
  if(count>0)
  {
         // not empty or null
   }
  else
  {
       // empty
  }
}

That won't work if listEnumerable is null, which is the question at hand
J
Jhollman

I use this one:

    public static bool IsNotEmpty(this ICollection elements)
    {
        return elements != null && elements.Count > 0;
    }

Ejem:

List<string> Things = null;
if (Things.IsNotEmpty())
{
    //replaces ->  if (Things != null && Things.Count > 0) 
}

R
Rob

Since some resources are exhausted after one read, I thought why not combine the checks and the reads, instead of the traditional separate check, then read.

First we have one for the simpler check-for-null inline extension:

public static System.Collections.Generic.IEnumerable<T> ThrowOnNull<T>(this System.Collections.Generic.IEnumerable<T> source, string paramName = null) => source ?? throw new System.ArgumentNullException(paramName ?? nameof(source));

var first = source.ThrowOnNull().First();

Then we have the little more involved (well, at least the way I wrote it) check-for-null-and-empty inline extension:

public static System.Collections.Generic.IEnumerable<T> ThrowOnNullOrEmpty<T>(this System.Collections.Generic.IEnumerable<T> source, string paramName = null)
{
  using (var e = source.ThrowOnNull(paramName).GetEnumerator())
  {
    if (!e.MoveNext())
    {
      throw new System.ArgumentException(@"The sequence is empty.", paramName ?? nameof(source));
    }

    do
    {
      yield return e.Current;
    }
    while (e.MoveNext());
  }
}

var first = source.ThrowOnNullOrEmpty().First();

You can of course still call both without continuing the call chain. Also, I included the paramName, so that the caller may include an alternate name for the error if it's not "source" being checked, e.g. "nameof(target)".


A
Ahmed Salem
 public static bool AnyNotNull<TSource>(this IEnumerable<TSource> source)
    {
        return source != null && source.Any();
    }

my own extension method to check Not null and Any


C
CodesInChaos

Without custom helpers I recommend either ?.Any() ?? false or ?.Any() == true which are relatively concise and only need to specify the sequence once.

When I want to treat a missing collection like an empty one, I use the following extension method:

public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> sequence)
{
    return sequence ?? Enumerable.Empty<T>();
}

This function can be combined with all LINQ methods and foreach, not just .Any(), which is why I prefer it over the more specialized helper functions people are proposing here.


R
Ron Chibnik

I use

    list.Where (r=>r.value == value).DefaultIfEmpty().First()

The result will be null if no match, otherwise returns one of the objects

If you wanted the list, I believe leaving of First() or calling ToList() will provide the list or null.


T
Truong Mai Van

it null will return true

enter    public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
    {

        try
        {
            return enumerable?.Any() != true;
        }
        catch (Exception)
        {

            return true;
        }
   
    }

code here


c
caldera.sac

just add using System.Linq and see the magic happening when you try to access the available methods in the IEnumerable. Adding this will give you access to method named Count() as simple as that. just remember to check for null value before calling count() :)