Reputation: 70307
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
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
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
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
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