none
Best practice for testing empty non-generic IEnumerable?

    Question

  • Is the best way to test if a System.Collections.IEnumerable is empty by calling GetEnumerator.MoveNext and testing for a False Boolean?

    I am working with a custom control that uses non-generic IEnumerable as an ItemsSource DependencyProperty.  The control is set up to cache the ItemsSource under certain circumstances, but it never caches a Null value or when the IEnumerable is empty.  Testing for Null is easy, but I am not sure if I am testing for empty in the best way.  Obviously, with IEnumerable<T> I can just call the Any method, but since I am using the non-generic, is GetEnumerator.MoveNext this the most efficient way to test for an empty IEnumerable?  Thoughts?

     

    Tuesday, March 9, 2010 6:43 PM

All replies

  • What about converting to an IEnumerable<Object> and then calling any?

    var items = control.ItemsSource;
    if ( items != null && items.OfType<Object>().Any() )
    {
        // do something
    }

    Does that work for you?

    Tuesday, March 9, 2010 10:20 PM
  • Thanks for replying.  My question is more about best practices.  The GetEnumerator.MoveNext method works just fine, I am just wondering if it is the best way to check for an empty IEnumerable. 

    Here is a purely fictional example to use:

    Class Widget
        Private _Value As Object
    
        Public Property Value() As Object
            Get
                Return Me._Value
            End Get
            Set(ByVal value As Object)
                Me._Value = value
            End Set
        End Property
    End Class
    
    Class WidgetList
        Inherits List(Of Widget)
    End Class

     Now, I set an empty WidgetList as my ItemsSource (which accepts System.Collections.IEnumerable)   Internally, I do a check to see if the IEnumerable is empty.  There are different options for doing this:

    1.  If I use ItemsSource.GetEnumerator.MoveNext, False is returned and I know this is an empty enumerable.

    2.  If I use ItemsSource.OfType(Of Object).Any() or ItemsSource.Cast(Of Object).Any() then False would also be returned.

    In these two examples, I would assume #1 to be more efficient since, in #2, each item in the Widget collection would be cast to an Object before being tested for Any.  In a non-empty collection, this would result in more processing, whereas I assume GetEnumerable.MoveNext would call the non-generic GetEnumerator implementation of List<T> and convert only the first item to an Object.

    Bottom line is that it is a minor issue, but I am curious about the best way of doing this and if anyone can shed some light on the inner workings of the Enumerable that might help answer this.  For example, is there any internal optimization on IEnumerable<T> that would make it a better choice or performance cost of calling the non-generic GetEnumerator that would make it a worse choice just to check for one item?  Obviously an empty collection incurs little performance cost, but when it could just as easily be a non-empty collection with thousands of items, I want to make sure I am using best coding practice.  Thanks!

    Wednesday, March 10, 2010 5:00 AM
  • Thanks to MarcGravell on StackOverflow for the below solution (see comment thread on this answer for the original solution).

     
     public static bool Any(this IEnumerable enumerable) 
     {
         if (enumerable == null)
             throw new ArgumentNullException(nameof(enumerable));
         if (enumerable is ICollection enumerableAsICollection)
             return enumerableAsICollection.Count != 0;
         var iter = enumerable.GetEnumerator();
         using (iter as IDisposable) //ensure iter is correctly disposed of if the enumerator implements IDisposable
             return iter.MoveNext();
     }
    

    Thursday, November 22, 2018 12:06 PM