在.NET泛型接口中,ICollection<T>
本身具有Count
属性。但它不会继承任何具有 Count
属性的非泛型接口。
所以,现在如果你想确定非泛型IEnumerable
的计数,你必须检查它是否在实现ICollection
,如果没有,你必须使用反射来查找它是否实现了泛型ICollection<X>
,因为你不知道泛型参数X
。
如果ICollection<T>
不能直接从ICollection
继承,为什么没有另一个只有Count
属性的非泛型接口?
只是糟糕的设计选择吗?
更新:为了使问题更清晰,我在当前的实现中演示了该问题:
static int? FastCountOrZero(this IEnumerable items)
{
if (items == null)
return 0;
var collection = items as ICollection;
if (collection != null)
return collection.Count;
var source = items as IQueryable;
if (source != null)
return QueryableEx.Count(source);
// TODO process generic ICollection<> - I think it is not possible without using reflection
return items.Cast<object>().Count();
}
只是糟糕的设计选择吗?
答案可能是肯定的。
为了解决这个问题,在.NET 4.5 MS中引入了IReadOnlyCollection<out T>
接口,该接口对于引用类型是协变的。
因此,您可以像下面这样重写代码
static int? FastCountOrZero(this IEnumerable items)
{
if (items == null)
return 0;
var collection = items as ICollection;
if (collection != null)
return collection.Count;
var roCollection = items as IReadOnlyCollection<object>; // only for reference types
if (roCollection != null)
return roCollection.Count;
var source = items as IQueryable;
if (source != null)
return QueryableEx.Count(source);
return items.Cast<object>().Count();
}
作为最后的手段,您可以将items
强制转换为动态对象并动态调用Count
属性。
if (items.GetType().GetInterface("System.Collections.Generic.ICollection`1") != null)
{
dynamic dynamic = items;
return dynamic.Count;
}
我能建议的最好的就是这个。注意(如注释中所述,Ienumerable 可以是无限的)
public static int CountIEnumerable (IEnumerable t)
{
var iterator = t.GetEnumerator();
var max = int.MaxValue;
int count = 0;
while (iterator.MoveNext() && (count < max))
{
count++;
}
//OPTIONAL
//if (count >= max)
//{
// throw new Exception("Collection is too big");
//}
return count;
}
编辑:您可以将"int"替换为 Int64 :)