IEnumerable<T>
interface is covariant, so IEnumerable<string>
is IEnumerable<object>
.
But why IEnumerable<int>
is not IEnumerable<object>
while int
is object
?
CodePudding user response:
Variance conversions like this are only supported if there is an implicit reference or identity conversion between the type parameters. As the spec says:
A type
T<Aᵢ, ..., Aᵥ>
is variance-convertible to a typeT<Bᵢ, ..., Bᵥ>
ifT
is either an interface or a delegate type declared with the variant type parametersT<Xᵢ, ..., Xᵥ>
, and for each variant type parameterXᵢ
one of the following holds:
Xᵢ
is covariant and an implicit reference or identity conversion exists fromAᵢ
toBᵢ
Xᵢ
is contravariant and an implicit reference or identity conversion exists fromBᵢ
toAᵢ
Xᵢ
is invariant and an identity conversion exists fromAᵢ
toBᵢ
There is neither a reference not identity conversion between int
and object
, only a boxing conversion.
You might be wondering what's so special about implicit reference and identity conversions, that they allow variance conversions. Well, these conversions don't require the runtime to do anything at all!
To convert from a string
to object
, for example, is purely a compile-time matter. Nothing needs to be done to the bits representing the string
, in order to turn it into an object
. After all, every string
is an object
.
Because of this, converting from IEnumerable<string>
to IEnumerable<object>
is trivial too - the runtime does not need to do anything.
This is not true for the int
-to-object
conversion, however. Because int
is a value type and object
is a reference type. to maintain these semantics, the runtime needs to create a reference type wrapper around that int
in order to do the conversion, "boxing" it.
This means that the runtime cannot just "do nothing" if it wants to convert a IEnumerable<int>
to IEnumerable<object>
. You would expect to get reference types out of that IEnumerable
, not value types, so when and how does the "boxing" happen? When and how should this happen in general, not just in the case of IEnumerable<T>
?
I'm sure this in theory can all be figured out, designed, and implemented, but it would certainly not be as trivial as the case with implicit reference conversions. In fact, I reckon it would be a lot more complicated and very drastic changes to both the language and runtime would be needed, which is probably why this is not implemented.
CodePudding user response:
Int is a value type while string is a reference type. Thus int is not an object whilst string is one.
See also here.