Casting from IEnumerable<Object> to IEnumerable<string>

16,153

Solution 1

The technical term for this is that generics are invariant in C# 3.0 and earlier. From C#4.0 onward, the cast works.

What invariant means is that there is no relationship between two generic types just because their generic type parameters are related (i.e. are sub- or supertypes of each other).

In your example, there is no typing relationship between an IEnumerable<object> and an IEnumerable<string>, just because string is a subtype of object. They're just considered two completely unrelated types, like a string and an int (they still both are subtypes of object, but everything is)

There are a few workarounds and exceptions for this issue you've run into.

First, you can cast each string individually to object, if you're using .NET 3.0 you can do that using the Cast<T>() extension method. Otherwise, you can use a foreach and put the result into a new variable of the static type you want.

Second, arrays are an exception for reference type, i.e. passing in a string[] type to a method acccepting object[] types should work.

Solution 2

As others have pointed out, generics types are invariant. IEnumerable<T> could be co-variant but C# doesn't currently support specifying variants. C# 4.0 is expected to support variants so this might be supported in the future.

To work around this now you can using a the LINQ extension method Cast<object>(). Assuming you have a method called Foo that takes an IEnumerable<object>>. You can call it like this,

Foo(stringEnumerable.Cast<object>());

Solution 3

The easiest way to pass IEnumerable<string> to function requiring IEnumerable<object> is through converting function like this:

public IEnumerable<object> convert<T>(IEnumerable<T> enumerable)
    {
    foreach (T o in enumerable)
        yield return o;
    }

When C# 4 comes out, this won't be neccessary, because it will support covariance and contravariance.

Share:
16,153
Embedd_0913
Author by

Embedd_0913

Updated on June 24, 2022

Comments

  • Embedd_0913
    Embedd_0913 almost 2 years

    Recently I found a very surprising behavior in c#. I had a method which takes IEnumerable<Object> as a parameter and i was passing IEnumerable<string> but it's not possible. While in c# everything can be upcast to Object than why this is not possible? It's totally confusing for me. Please someone clear me on this issue.

    • Jon Limjap
      Jon Limjap about 15 years
      How is it not possible? Is it throwing an ArgumentException? Besides, what's the point of using a generic IEnumerable if you're going to declare it as an Object?
    • Daniel Earwicker
      Daniel Earwicker about 15 years
  • Meydjer Luzzoli
    Meydjer Luzzoli about 15 years
    IEnumerable<T> doesn't have an Add method though... And in C# 4.0 you will actually be able to perform this cast as the declaration will change to IEnumerable<out T> allowing it to be (safely) contravariant.
  • Jon Skeet
    Jon Skeet about 15 years
    This is exactly what Cast<> is for :)
  • 1800 INFORMATION
    1800 INFORMATION about 15 years
    Well substitute any generic class that does have an Add method like List then
  • Sam Harwell
    Sam Harwell about 14 years
    -1: IEnumerable<T> becomes IEnumerable<out T> in .NET 4 specifically because your argument makes sense for a container but not for an enumeration.
  • Paul Tyng
    Paul Tyng over 12 years
    Just to update this older answer, covariance and contravariance are now supported in C#, and this is now a valid cast.