Jonathan Allen
Jonathan Allen

Reputation: 70307

How do I get the count from ICollection<T> with an unknown T

Here is my code so far:

//TODO: Look for a way of handling ICollection<T>

if (value is ICollection)
{
    return CreateResult(validationContext, ((ICollection)value).Count);
}

if (value is IEnumerable)
{
    var enumerator = ((IEnumerable)value).GetEnumerator();
    try
    {
        var count = 0;
        while (enumerator.MoveNext())
            count++;
        return CreateResult(validationContext, count);
    }
    finally
    {
        if (enumerator is IDisposable)
            ((IDisposable)enumerator).Dispose();
    }

}

Is there a good way of getting the Count out of ICollection<T> without resorting to iterating over the collection?

Upvotes: 4

Views: 3273

Answers (4)

Sean Barlow
Sean Barlow

Reputation: 588

Both the ICollection and IEnumerable Interfaces have a property for Count. The generic versions as well.

if (value is ICollection)
{
    return CreateResult(validationContext, ((ICollection)value).Count);
}

if (value is IEnumerable)
{
     return CreateResult(validationContext, ((IEnumerable)value).Count);
}

MSDN Documentation for ICollection http://msdn.microsoft.com/en-us/library/system.collections.icollection.aspx

MSDN Documentation for IEnumerable http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx

Upvotes: -1

Christopher Currens
Christopher Currens

Reputation: 30695

Reflection would be the way to go, but keep in mind that most of the Collections in the FCL inherit from both ICollection<T> and ICollection So code like this works:

var collection = new List<int>();
Console.WriteLine(collection is ICollection<MyClass>);
Console.WriteLine(collection is ICollection);

True is output for both. This works for most, if not all, collections in the FCL. If you needed it to work against custom collections, or collections that don't implement ICollection, then reflection is the only way.

Sidenote: Arrays also implicitly implement ICollection, IList and IEnumerable (the CLR actually generates an array that inherits from the generic versions of those classes in addition to the non-generic at runtime), so your above code would work with arrays as well.

Upvotes: 1

Peter Oehlert
Peter Oehlert

Reputation: 16938

Without having the closed type of ICollection<T>, you'd have to resort to reflection to call the Count property.

if (typeof(ICollection<>) == value.GenericTypeDefinition()) {
  var countProp = value.GetType().GetProperty("Count");
  var count = (int)countProp.GetValue(value, null);
}

Upvotes: 6

Ani
Ani

Reputation: 113402

You'll have to use reflection:

var genCollType = value.GetType()
                       .GetInterfaces()
                       .FirstOrDefault
                           (i => i.IsGenericType 
                              && i.GetGenericTypeDefinition() == typeof(ICollection<>));

if (genCollType != null)
{
    int count = (int)genCollType.GetProperty("Count")
                                .GetValue(value, null);

    return CreateResult(validationContext, count);   
}

Upvotes: 4

Related Questions