Самая простая форма будет:
public static int Count(this IEnumerable source)
{
int c = 0;
using (var e = source.GetEnumerator())
{
while (e.MoveNext())
c++;
}
return c;
}
Вы можете улучшить это, запросив 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;
}
Обновление
Как отмечает Джерард в комментариях, неуниверсальный IEnumerable
не наследует IDisposable
, поэтому обычный оператор using
не будет работать. Вероятно, все еще важно попытаться избавиться от таких перечислителей, если это возможно - метод итератора реализует IEnumerable
и может быть косвенно передан этому методу Count
. Внутренне этот метод итератора будет зависеть от вызова Dispose
для запуска своих собственных операторов try
/ finally
и using
.
Чтобы упростить это и в других обстоятельствах, вы можете сделать свою собственную версию оператора using
, которая будет менее суетной во время компиляции:
public static void DynamicUsing(object resource, Action action)
{
try
{
action();
}
finally
{
IDisposable d = resource as IDisposable;
if (d != null)
d.Dispose();
}
}
И обновленный метод Count
будет тогда:
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;
}