很明显,T[]
数组类型不是covariant,因为T[]
的元素可以通过索引设置。
然而,只要U[]
来自T[]
,U
就可以投放到T
而不会受到编译器的任何投诉。
Man[] men = new[] { new Man("Aaron"), new Man("Billy"), new Man("Charlie") };
Person[] people = (Person[])men;
在上面的代码中,men
和people
似乎确实拥有对同一Array
个对象的引用。设置men[0] = new Man("Aidan")
的效果可以在people[0]
看到。同样,尝试people[0] = new Woman("Debbie")
会在运行时产生ArrayTypeMismatchException
。
这是否意味着T[]
类型实际上对每个set
调用执行类型检查?如果允许以这种方式转换数组,这似乎是必要的。
我想我的问题只是:这怎么可能?我很清楚,U[]
并非来自T[]
。对我来说也是不清楚我是否可以定义我自己的类型以这种方式工作:实际上是不变但行为协变。
*虽然 CLR 显然允许数组差异,但任何语言都可能禁止在数组类型之间进行转换。但是,似乎这种行为在VB.NET中是相同的:
Dim men = New Man() { New Man("Aaron"), New Man("Billy"), New Man("Charlie") }
Dim people = CType(men, Person())
答案 0 :(得分:7)
这是数组的特殊行为,不能以任何其他类型复制。
答案 1 :(得分:2)
这只是因为它是CLR的一部分的特殊功能。数组是自动协变的,即使技术上它们不是。编译器只需知道这一点并生成正确的类型检查。
虽然有些人认为此功能是错误的,但在类型安全集合和通用接口协方差之前进行此操作非常重要。如果没有它,您甚至无法编写一个函数来对数组进行排序。
答案 2 :(得分:1)
Eric在这里非常清楚地解释道:http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx。
短简历:如果D继承B,则D []与B []协变。假设D2也继承自B,那么
B[] b = new D[10];
b[0] = new D1();
抛出异常。是的,这不好,但确实如此。