谁能帮我一个IEnumerable
(非通用接口)的Count
扩展方法?
我知道它在LINQ中不受支持,但如何手动编写?
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;
}
}
最简单的形式是:
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;
}
正如Gerard在评论中指出的那样,非泛型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;
}
不同类型的IEnumerable有不同的确定计数的最佳方法;不幸的是,没有通用的方法可以知道哪种方法最适合任何给定的IEnumerable,甚至也没有任何标准的方法可以让IEnumerable指出以下哪种技术是最好的:
- 直接询问对象。一些支持IEnumerable的对象类型,如Array、List和Collection,具有可以直接报告其中元素数量的属性。
- 枚举所有项,丢弃,并统计枚举的项数。
- 将所有项目枚举到列表中,然后在需要再次使用枚举时使用该列表。
我认为选择的类型来表示你的元素序列应该是ICollection而不是IEnumerable,首先。
ICollection
和ICollection<T>
都提供了Count属性,并且每个iccollection都实现了ienumerable