C# 正在计算IEnumerable的计数(非泛型)
有人能帮我介绍一下C# 正在计算IEnumerable的计数(非泛型),c#,.net,linq,extension-methods,ienumerable,C#,.net,Linq,Extension Methods,Ienumerable,有人能帮我介绍一下IEnumerable(非通用接口)的Count扩展方法吗 我知道LINQ不支持它,但如何手动编写它?最简单的形式是: public static int Count(this IEnumerable source) { int c = 0; using (var e = source.GetEnumerator()) { while (e.MoveNext()) c++; } return c;
IEnumerable
(非通用接口)的Count
扩展方法吗
我知道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;
}
更新
正如Gerard在评论中指出的,非泛型IEnumerable
不会继承IDisposable
,因此正常的using
语句将无法工作。如果可能,尝试处理此类枚举数可能仍然很重要-迭代器方法实现IEnumerable
,因此可能会间接传递给此Count
方法。在内部,该迭代器方法将取决于对Dispose
的调用,以触发它自己的try
/最终使用和语句
为了在其他情况下简化此操作,您可以使用编译时不太繁琐的
语句来创建自己的版本:
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的某些类型的对象(如数组、列表和集合)的属性可以直接报告其中的元素数。
枚举所有项目,丢弃它们,并计算枚举的项目数。
将所有项目枚举到列表中,然后在需要再次使用枚举时使用该列表。
在不同的情况下,上述每一项都将是最佳的。我认为,首先,用于表示元素序列的类型应该是ICollection,而不是IEnumerable
ICollection
和ICollection
都提供了一个Count属性,加上-每个ICollection也实现了IEnumerable。“查询IList”-或查询其基本接口ICollection我尝试了这个扩展,使用
为System.Collections.IEnumerable
提供了一个编译错误。我将代码更改为编译的Count(此IEnumerable源代码)
。@Daniel检查ICollection
的答案更好,因为它值得…@Marc第一个.Cast().Count()
已经进行了检查(通用和非通用)。但是是的,第二个解决方案可以通过检查来改进。将其转换为通用IEnumerable版本有什么意义?这将消除使用非泛型IEnumerable背后的原因——正是在您不知道/不关心元素类型的情况下。因此,您将无法对元素类型执行任何编译时强制转换,因为它们未知(如果已知-使用的IEnumerable首先应该是泛型的)。如果最终需要的是获取元素总数的方法,那么对象类型可能不应该是IEnumerable,而应该是ICollection。通用和非通用版本都提供了计数属性。我同意编辑答案中的“过早优化”论点。
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;
}
}