Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking if a generic IEnumerable is empty

Tags:

c#

linq

generics

Let's say I have an object which may be of type IEnumerable<T>. I want to write a method that returns true if the object is of type IEnumerable<T>, is not null, and is not empty.

Here's what I've got so far:

public bool IsNullOrEmpty(object obj)
{
    if (obj != null)
    {
        if (obj is IEnumerable<object>)
        {
            return (obj as IEnumerable<object>).Any();
        }
    }
    return false;
}

This works if I pass in an object that is of type List<string>, but not if I pass in an object that is of type List<int>. It fails because because obj is IEnumerable<object> returns false.

Any idea how I can make this work for all generic IEnumerables?

like image 966
K Mehta Avatar asked Sep 04 '14 21:09

K Mehta


Video Answer


4 Answers

Since the type may be unknown, you can try check for IEnumerable interface and use MoveNext() on the enumerator.

EDIT: I updated the method name. It makes more sense with the logic now since the original question code was checking if there were items in the collection.

public bool IsNotNullOrEmpty(object enumerable)
{
    if (enumerable != null)
    {
        if (enumerable is IEnumerable)
        {
            using(var enumerator = ((IEnumerable)enumerable).GetEnumerator())
                return enumerator.MoveNext();
        }
    }
    return false;
}
like image 157
TyCobb Avatar answered Sep 20 '22 20:09

TyCobb


System.Collections.Generic.IEnumerable<T> inherits from System.Collections.IEnumerable - thus, if you are ok with checking the non-generic IEnumerable, rather than the generic IEnumerable<T>, you could just cast to IEnumerable.

A few notes about your code: You are first checking with is, and then you cast with as. That is generally unnecessary; as already checks and returns null if the cast failed. Therefore, a shorter way would be:

var enumerable = obj as IEnumerable;
if (enumerable != null) {
    return !enumerable.Cast<object>().Any();
}

Note that you will need the additional call to Cast there, as Any requires a generic IEnumerable<T>.

like image 25
O. R. Mapper Avatar answered Sep 20 '22 20:09

O. R. Mapper


You can try to cast it to IEnumerable:

public static bool IsNullOrEmpty<T>(this T obj) where T : class
{
    if (obj == null) return true;
    IEnumerable seq = obj as IEnumerable;
    if (seq != null) return !seq.Cast<object>().Any();
    return false;
}

...

List<int> list = new List<int>();
bool nullOrEmpty = list.IsNullOrEmpty();  // true

Btw, interestingly enough it works correctly with an empty string:

bool nullOrEmpty = "".IsNullOrEmpty();   // true
like image 22
Tim Schmelter Avatar answered Sep 22 '22 20:09

Tim Schmelter


You can check for the non-generic IEnumerable and check that for emptiness. You can add a check to ensure the object implements IEnumerable<T> using reflection:

public static bool IsNullOrEmpty(object obj)
{
    var e = obj as System.Collections.IEnumerable;
    if (e == null || !e.GetType().GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))) return false;

    foreach (object _ in e)
    {
        return true;
    }
    return false;
}
like image 44
Lee Avatar answered Sep 22 '22 20:09

Lee