为什么C#数组是协变的,它带来了什么好处?

我无法理解为什么C#中的数组是协变的,以及这种协方差带来的好处。 考虑以下简单的代码示例:

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

这段代码可以正常编译,但是会毫不客气地在运行时爆炸。

如果我尝试使用generics尝试同样的事情,编译器会抱怨我,我会在早期意识到我的愚蠢,所以我的问题是:为什么C#编译器允许这种与数组的协方差,而且,什么是潜在的好处?

Eric Lippert说:

不幸的是,这种特殊的协方差被打破了。 它被添加到CLR中,因为Java需要它,而CLR设计者希望能够支持类似Java的语言。 然后我们将它添加到C#,因为它在CLR中。 这个决定当时颇具争议,我对此并不十分满意,但现在我们无能为力。

埃里克·利珀特(Eric Lippert)有一篇关于此的文章(实际上是关于’方差’的长篇系列,我认为11部分)

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

还有一些更有意思的东西

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

在许多情况下,代码将在数组的插槽之间移动或复制项目。 如果Arr是具有至少两个元素的一维数组,则无论Arr的类型或其中包含的元素如何,以下代码都将起作用。

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

如果Arr是值类型,则此代码效率低,但由于从数组中读取temp ,因此保证数组的类型能够保存这样的值。 代码必须使用box和unbox值类型元素,因此这些类型的效率会很低,但无论如何都会有效。

请注意,虽然使数组协变是允许排序方法在任意数组类型上工作的一种方法,但它并不是唯一的方法。 另一种方法是让System.Array包含一些方法和属性,其参数与底层元素类型无关。 例如,它可以包括一些简单的方法,如SwapCopyItemRoll ,以及可能的方法,在给定索引列表的情况下执行更复杂的排列。 请注意,与上面显示的代码不同,类似Int[]的类型可以以避免装箱和取消装箱的方式覆盖其Swap方法。