views:

442

answers:

5

I'm trying to find the most reusable, yet elegant, piece of code possible for determining if an IEnumerable. In the ideal, this should be a function I can call absolutely any time I need to tell if an IEnumerable is empty.

While I have developed an answer for .NET 3.5 that has worked well for me so far, my current thought is that there is no perfect answer, since an IEnumerable can technically encapsulate a collection (or queue of iterators) that modifies the underlying results as it iterates, which would cause problems. However, this would also be an impediment to implementing IEnumerable.Count(), and that didn't stop MS from providing it.

So I thought I'd put it to SO to see if someone has a better one, and in case someone else should find it useful.

Edit: Wow, I can't believe I didn't know about IEnumerable.Any. I knew it existed, but never bothered to check what it did. Let this be a lesson. Read the documentation. Just because a method name doesn't imply it does what you want, doesn't mean it doesn't do what you want.

+17  A: 

!enumerable.Any()

Will attempt to grab the first element only.

To expand on how/why this works, any determines if any of the components of an IEnumerable match a given function, if none is given, then any component will succeed, meaning the function will return true if an element exists in the enumerable.

Guvante
Wow.... Can't believe I didn't know about this. Thanks!
Chris Ammerman
It's new in .Net 3.5
Keith
+2  A: 

For .net 1/2:

IEnumerator e;
try
{
   e = enumerable.GetEnumerator();
   return e.MoveNext();
}
finally
{ 
    if (e is IDisposable)
        e.Dispose();
}

Or, with generics:

using (IEnumerator<T> e = enumerable.GetEnumerator())
{
    return e.MoveNext();
}
Matt
A: 

One thing to be careful of with either of these methods is that not all enumerations can be rolled-back, for instance all implementations of System.Data.IDataReader can only run through once.

In these cases you don't really have a cost in a foreach loop, so long as you account for the fact that it might not even loop once.

Keith
+2  A: 

You're right that there is no perfect answer. IEnumerable only supports iteration and doesn't guarantee that the enumeration is repeatable. You can't find out if an enumeration contains elements without calling MoveNext at least once, and once you've done so you can't guarantee to be able to reuse the enumeration: it is allowable for IEnumerable.Reset to throw a NotSupportedException. From http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset.aspx:

"The Reset method is provided for COM interoperability. It does not necessarily need to be implemented; instead, the implementer can simply throw a NotSupportedException."

Extension methods like IEnumerable<T>.Count and IEnumerable<T>.Any need to call MoveNext under the covers. Useful wrappers, but don't avoid the fact that in the (rare) cases where an enumeration doesn't support Reset, you could have a problem.

Joe
Understood, but I think that any code that operates on IEnumerable instances in ways other than to add more iterators onto the queue (yield return) is going to have this risk.
Chris Ammerman
A: 

The first method has a simple implementation of Empty extension method: http://signum.codeplex.com/SourceControl/changeset/view/25903#510468

Olmo