Generics supports only reference conversions not boxing conversions

While reading c# in a nutshell about boxing and unboxing on page 91, author writes this:

Boxing conversions are crucial in providing a,unified type system. The system is not perfect, however we will see in Generics that variance with arrays and generics supports only **reference conversions ** and not **boxing conversions **

And quoted example code:

object [] a1 = new string [3]; //legal
object [] a2 = new int [3]; // error

Can somebody explain what the author is trying to deliver and why the first line is legal and second line is not?

Jon Skeet
people
quotationmark

Well, there's a reference conversion between string and object, in that every string reference can be treated as an object reference. This can be done transparently, with no modification to the value at all. That's why array variance can be done cheaply - for reads, anyway. Reading from an object[] value (as is known at compile-time) which happens to really be a string[] at execution time is basically free - you read the value, and you can treat it as an object reference. Writing is more painful - every write to an object[] has to check that the value you're writing is genuinely compatible with the array you're trying to store it in.

The important thing here is that the representation of a string reference is the same as the representation of an object reference.

There's a boxing conversion between int and object which lets this work:

int x = 10;
object y = x;

... but that conversion involves more action; the CLR has to create an object which contains the relevant integer. The representation of an int is not the same as the representation of an object reference. Checking whether that's necessary - and doing it as you go - would be relatively painful (from a performance perspective) when reading from an array, so it's not valid to treat an int[] as an object[].

The same is true for generic variance. This is fine:

List<string> strings = new List<string>();
IEnumerable<object> objects = strings; // IEnumerable<T> is covariant in T

But this isn't:

List<int> ints = new List<int>();
IEnumerable<object> objects = ints; // Covariance doesn't apply here

For more on representation and identity, see Eric Lippert's blog post on the topic. (It doesn't talk about variance very much, but it's all related...)

people

See more on this question at Stackoverflow