Может ли кто-нибудь помочь мне с расширением Count
для IEnumerable
(не общий интерфейс).
Я знаю, что он не поддерживается в LINQ, но как писать его вручную?
Может ли кто-нибудь помочь мне с расширением Count
для IEnumerable
(не общий интерфейс).
Я знаю, что он не поддерживается в LINQ, но как писать его вручную?
Простейшая форма:
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;
}
yourEnumerable.Cast<object>().Count()
К комментарию о производительности:
Я думаю, что это хороший пример преждевременной оптимизации, но здесь вы идете:
static class EnumerableExtensions
{
public static int Count(this IEnumerable source)
{
int res = 0;
foreach (var item in source)
res++;
return res;
}
}
Различные типы IEnumerable имеют разные оптимальные методы для определения count; к сожалению, нет универсальных средств для определения того, какой метод будет наилучшим для любого заданного IEnumerable, и нет даже стандартных средств, с помощью которых IEmumerable может указать, какой из следующих методов лучше всего:
Каждое из указанных выше будет оптимальным в разных случаях.
Я думаю, что тип, выбранный для представления вашей последовательности элементов, должен был быть ICollection вместо IEnumerable, в первую очередь.
Оба ICollection
и ICollection<T>
предоставляют свойство Count - plus - каждый ICollection также реализует IEnumearable.