简体   繁体   中英

Why generic ICollection<T> does not inherit some non-generic interface with Count property?

In .NET generic interface ICollection<T> has Count property itself. But it does not inherit any non-generic interface with a Count property.

So, now if you want determine count of non-generic IEnumerable , you have to check whether it is implementing ICollection and if not, you have to use reflection to lookup whether it does implement generic ICollection<X> , since you do not know the generic argument X .

If ICollection<T> cannot inherit from directly from ICollection , why there is not another non-generic interface with Count property only?

Is it just bad design choice?

UPDATE : To make the question more clear, I demonstrate the issue on my current implementation:

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

Is it just bad design choice?

Probably the answer is yes .

And to solve this issue in .NET 4.5 MS introduced IReadOnlyCollection<out T> interface, which is covariant for reference types.

So you can rewrite your code like following

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

And as last resort you can cast items to dynamic object and invoke Count property dynamicly.

if (items.GetType().GetInterface("System.Collections.Generic.ICollection`1") != null)
{
    dynamic dynamic = items;
    return dynamic.Count;
}

Best I can propose is this. Note (As mentioned in comments, Ienumerable can be infinite)

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

Edit : You can replace "int" by Int64 :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM