Why are C# arrays covariant and what benefits does

2020-03-13 15:21发布

问题:

I'm having trouble understanding why arrays in C# are covariant and what benefits this covariance can bring. Consider the following trivial code example:

object[] myArray = new string[1];
myArray[0] = 1;

This code will compile okay, but will unceremoniously and perhaps unsurprisingly explode at runtime.

If I try to attempt this same thing using generics, the compiler would grumble at me and I would realise my stupidity at an early stage, so my question is this: Why does the C# compiler allow this covariance with arrays and furthermore, what are the potential benefits?

回答1:

Eric Lippert says:

Unfortunately, this particular kind of covariance is broken. It was added to the CLR because Java requires it and the CLR designers wanted to be able to support Java-like languages. We then up and added it to C# because it was in the CLR. This decision was quite controversial at the time and I am not very happy about it, but there’s nothing we can do about it now.



回答2:

Eric Lippert has a writeup about this (Actually a long series about 'variance', 11 parts I think)

http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx

And some more interesting stuff

http://blogs.msdn.com/b/ericlippert/archive/2009/09/24/why-is-covariance-of-value-typed-arrays-inconsistent.aspx



回答3:

There are many situations in which code will move or copy items between slots of an array. Provided that Arr is a single-dimensional array with at least two elements, the following code will work regardless of the type of Arr or the elements contained therein.

Object temp = Arr[1];
Arr[1] = Arr[0];
Arr[0] = temp;

This code will be inefficient if Arr is a value type, but since temp is read out of the array, the type of the array is guaranteed to be capable of holding such a value. The code will have to box and unbox value-type elements, and will thus be inefficient with such types, but it will work regardless.

Note that while making arrays covariant is one way to allow things like sorting methods to work on arbitrary array types, it's not the only one. Another approach would be to have System.Array include a few methods and properties whose parameters have no relation to the underlying element type. For example, it could include some simple methods like Swap, CopyItem, and Roll, and possibly methods to perform more complex permutations given a list of indices. Note that unlike the code shown above, a type like Int[] could override its Swap method in such fashion as to avoid boxing and unboxing.