'Why can't I assign List<int> to IEnumerable<object> in .NET 4.0

I try to do this:

IEnumerable<object> ids = new List<string>() { "0001", "0002", "0003" };

it works great!

But when I try to do this:

IEnumerable<object> intIds = new List<System.Int32>() { 1, 2, 3 };

Visual Studio tells me: Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists (are you missing a cast?)

Why is that?



Solution 1:[1]

Simply put: generic variance in .NET 4 doesn't support variance for type arguments which are value types.

The reason it can work for reference types is that once the CLR has decided it knows the generic conversion is safe, it can treat all reference values the same way - they have the same representation internally. No actual conversion is required to turn a string reference into an object reference, or vice versa if you know it's definitely a reference to a string - it's the same bits, basically. So the generated native code can just treat the references as references, happy in the knowledge that the rules around variance have guaranteed that nothing nasty will happen at the type safety level, and not performing any conversions on the values themselves.

That isn't true for value types, or for reference types where the conversion isn't a "reference conversion" (i.e. a representation-preserving one). That's why you can't write IEnumerable<XName> names = new List<string>(); by the way...

Solution 2:[2]

From MSDN Blogs > C# Frequently Asked Questions > Covariance and Contravariance FAQ:

Variance is supported only if a type parameter is a reference type. Variance is not supported for value types. The following doesn’t compile either:

// int is a value type, so the code doesn't compile.
IEnumerable<Object> objects = new List<int>(); // Compiler error here.

Solution 3:[3]

Another solution would be to use the extension method Enumerable.Cast as such:

Dim a as IEnumerable(Of Integer) = GetA()

MethodThatTakesIEnumerableOfObject(a.Cast(Of Object))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jon Skeet
Solution 2 Mark Byers
Solution 3 Klepto