问题
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?
回答1:
int
is a value type and can only be boxed to object
- it doesn't inherit from object
. Since you're using an IEnumerable<object>
anyway, this should work:
IEnumerable intIds = new List<int>() { 1, 2, 3 };
回答2:
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...
回答3:
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.
回答4:
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))
来源:https://stackoverflow.com/questions/8175311/why-cant-i-assign-listint-to-ienumerableobject-in-net-4-0