5

I have propertyValue which is an object passed into my function.

I can assume that this is an IEnumerable of some kind, however due to the interface contract I must accept it as an object rather than directly as an IEnumerable.

When I try to cast my value to an IEnumerable<object>, so that I can get the length, I get an InvalidCastException.

var length = ((IEnumerable<object>) propertyValue).Cast<object>().Count();

I get the following exception:

System.InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Collections.Generic.IEnumerable`1[System.Object]'.

cнŝdk
  • 31,391
  • 7
  • 56
  • 78
James Monger
  • 10,181
  • 7
  • 62
  • 98

4 Answers4

7

The IEnumerable<T> interface is covariant, but covariance doesn't work with value types. Casting a value type to reference type changes representation - the value needs to be boxed and the reference to the boxed value is returned. Casting reference types doesn't change representation - it's still the same reference, referencing the same object.

string is an IEnumerable<char>, so it cannot be cast to IEnumerable<object>.

As mentioned in other answers, the solution is to cast to non-generic IEnumerable.

var length = ((IEnumerable) propertyValue).Cast<object>().Count();
Jakub Lortz
  • 14,616
  • 3
  • 25
  • 39
3

I have fixed the issue by simply casting to IEnumerable rather than casting to IEnumerable<object>.

var length = ((IEnumerable) propertyValue).Cast<object>().Count();
James Monger
  • 10,181
  • 7
  • 62
  • 98
1

String implements the IEnumerable<char> interface, you can cast it to this interface

var length = ((IEnumerable<char>) propertyValue).Count();

For unknown types of collection you can cast it to IEnumerable and next enumerate values manually with your own extension method.

static class EnumerableExtensions
{
    public static int Count(this IEnumerable source)
    {
        int res = 0;

        foreach (var item in source)
            res++;

        return res;
    }
}

var collection = propertyValue as IEnumerable;
if(collection != null)
{
    var length = collection.Count();
}

Using Cast() method will cause to boxing of value types and it may have an performance issues for big collections.

Community
  • 1
  • 1
Vadim Martynov
  • 8,602
  • 5
  • 31
  • 43
0

The following code should actually do what you need

var length = (propertyValue as IEnumerable<object>).Count();      
dontbyteme
  • 1,221
  • 1
  • 11
  • 23