55

Can anyone help me with a Count extension method for IEnumerable (non generic interface).

I know it is not supported in LINQ but how to write it manually?

Homam
  • 23,263
  • 32
  • 111
  • 187

4 Answers4

60
yourEnumerable.Cast<object>().Count()

To the comment about performance:

I think this is a good example of premature optimization but here you go:

static class EnumerableExtensions
{
    public static int Count(this IEnumerable source)
    {
        int res = 0;

        foreach (var item in source)
            res++;

        return res;
    }
}
Lasse Espeholt
  • 17,622
  • 5
  • 63
  • 99
  • 4
    @Daniel's answer that checks for `ICollection` is better, for what it is worth... – Marc Gravell Apr 09 '11 at 11:48
  • 1
    @Marc The first `.Cast().Count()` already makes that check (generic and non-generic). But yes, the second solution could be improved by checks. – Lasse Espeholt Apr 09 '11 at 11:57
  • What's the point of casting it into the generic IEnumerable version ? This would defeat the reason behind using the non generic IEnumerable - exactly for when you do not know / do not care about the elements type. You will not, then, be able to do any compile-time casting to the elements type because they are not known (if they are known - the IEnumerable being used should be generic in the first place). – Veverke Nov 17 '15 at 10:25
  • If **all** what is needed in the end is a way of getting the total number of elements, perhaps the object type should not be IEnumerable but ICollection. Both the generic and non generic versions provide a Count property. – Veverke Nov 17 '15 at 10:29
  • I agree with "premature optimisation" argument in the edited answer. – Fabio Milheiro Sep 16 '16 at 18:45
50

The simplest form would be:

public static int Count(this IEnumerable source)
{
    int c = 0;
    using (var e = source.GetEnumerator())
    {
        while (e.MoveNext())
            c++;
    }
    return c;
}

You can then improve on this by querying for ICollection:

public static int Count(this IEnumerable source)
{
    var col = source as ICollection;
    if (col != null)
        return col.Count;

    int c = 0;
    using (var e = source.GetEnumerator())
    {
        while (e.MoveNext())
            c++;
    }
    return c;
}

Update

As Gerard points out in the comments, non-generic IEnumerable does not inherit IDisposable so the normal using statement won't work. It is probably still important to attempt to dispose of such enumerators if possible - an iterator method implements IEnumerable and so may be passed indirectly to this Count method. Internally, that iterator method will be depending on a call to Dispose to trigger its own try/finally and using statements.

To make this easy in other circumstances too, you can make your own version of the using statement that is less fussy at compile time:

public static void DynamicUsing(object resource, Action action)
{
    try
    {
        action();
    }
    finally
    {
        IDisposable d = resource as IDisposable;
        if (d != null)
            d.Dispose();
    }
}

And the updated Count method would then be:

public static int Count(this IEnumerable source) 
{
    var col = source as ICollection; 
    if (col != null)
        return col.Count; 

    int c = 0;
    var e = source.GetEnumerator();
    DynamicUsing(e, () =>
    {
        while (e.MoveNext())
            c++;
    });

    return c;
}
Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
  • 1
    "querying for IList" - or querying for it's base interface ICollection – Joe Apr 09 '11 at 10:11
  • 2
    I tried out this extension, the `using` gives a compile error for `System.Collections.IEnumerable`. I changed the code to `Count(this IEnumerable source)` which compiles. – Gerard May 13 '11 at 09:20
4

I think the type chosen to represent your sequence of elements should have been ICollection instead of IEnumerable, in the first place.

Both ICollection and ICollection<T> provide a Count property - plus - every ICollection implements IEnumearable as well.

AFract
  • 8,868
  • 6
  • 48
  • 70
Veverke
  • 9,208
  • 4
  • 51
  • 95
4

Different types of IEnumerable have different optimal methods for determining count; unfortunately, there's no general-purpose means of knowing which method will be best for any given IEnumerable, nor is there even any standard means by which an IEmumerable can indicate which of the following techniques is best:

  1. Simply ask the object directly. Some types of objects that support IEnumerable, such as Array, List and Collection, have properties which can directly report the number of elements in them.
  2. Enumerate all items, discarding them, and count the number of items enumerated.
  3. Enumerate all items into a list, and then use the list if it's necessary to use the enumeration again.

Each of the above will be optimal in different cases.

supercat
  • 77,689
  • 9
  • 166
  • 211