【问题标题】:Why generic ICollection<T> does not inherit some non-generic interface with Count property?为什么泛型 ICollection<T> 不继承某些具有 Count 属性的非泛型接口?
【发布时间】:2014-02-26 12:43:22
【问题描述】:

在 .NET 通用接口中,ICollection&lt;T&gt; 本身具有 Count 属性。但它不继承任何具有Count 属性的非通用接口。

所以,现在如果你想确定非泛型IEnumerable的数量,你必须检查它是否实现了ICollection,如果没有,你必须使用反射来查找它是否实现了泛型ICollection&lt;X&gt;,因为你不知道通用参数X

如果ICollection&lt;T&gt; cannot inherit from directly from 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();
    }

【问题讨论】:

  • IEnumerable 可能是无限的,所以 Count 不适用。
  • 为什么不使用coll.Count() 让.NET 确定它是否具有Count 属性?
  • @TN.: 那么你仍然可以使用enumerable.Cast&lt;object&gt;().Count(),因为它仍然实现ICollection,因此Enumerable.Count 将使用Count 属性而不是枚举所有。
  • @TN.:如果对象实现了ICollection,则可以。例如:IEnumerable enumerable = new List&lt;string&gt;(); enumerable = enumerable.Cast&lt;object&gt;(); int count = enumerable.Cast&lt;object&gt;().Count()。这仍将在后台使用 Count 属性。
  • @TimSchmelter 但是我可以通过转换为ICollection 直接解决这个问题。它对ICollection&lt;T&gt; 没有帮助。这是我的问题。 (因为ICollection&lt;T&gt; 不继承非泛型ICollection。)

标签: c# .net generics collections


【解决方案1】:

这只是糟糕的设计选择吗?

答案可能是是的

为了解决这个问题,在 .NET 4.5 MS 中引入了IReadOnlyCollection&lt;out T&gt; 接口,它对于引用类型是协变的。

所以你可以像下面这样重写你的代码

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;
}

【讨论】:

  • 对我来说 +1,谢谢你的提示 IReadOnlyCollection&lt;&gt;
【解决方案2】:

我能建议的最好的就是这个。注意(在cmets中提到,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 :)

【讨论】:

  • 这是幼稚的实现。但是如果有很多项目并且t 也实现了ICollection&lt;X&gt;,它可能会太慢。顺便提一句。您还应该检查iterator是否没有实现IDisposable,如果是,则必须释放迭代器才能释放资源。
猜你喜欢
  • 2013-01-11
  • 1970-01-01
  • 1970-01-01
  • 2010-09-18
  • 1970-01-01
  • 2015-11-18
  • 2021-10-27
  • 2020-03-02
  • 2014-03-05
相关资源
最近更新 更多