8

在阅读Wikipedia上一篇关于协变和逆变的文章时,我遇到了以下粗体句子:

首先考虑数组类型构造函数:从类型Animal我们可以创建类型Animal[](“动物数组”)。我们是否应该将其视为

  • 协变:aCat[]Animal[]
  • 逆变:aAnimal[]是aCat[]
  • 或者都不是(不变的)?

如果我们希望避免类型错误,并且数组同时支持读取和写入元素,那么只有第三种选择是安全的。显然,并不是每一个都Animal[]可以被视为 a Cat[],因为从数组中读取的客户端会期望一个 Cat,但 anAnimal[]可能包含例如 a Dog。所以逆变规则是不安全的。

相反, aCat[]不能被视为 a Animal[]应该始终可以将 aDog放入 aAnimal[]中。对于协变数组,这不能保证是安全的,因为后备存储实际上可能是一个猫数组。所以协变规则也不安全——数组构造函数应该是不变的。请注意,这只是可变数组的问题;协变规则对于不可变(只读)数组是安全的。

我理解这个概念;我只是想要一个例子来说明这个在 C# 中“不能保证是安全的”。

4

2 回答 2

19

在编译时不安全。换句话说,有些代码在语言规则下是合法的,但在执行时失败,没有任何明确的强制转换来给出“这可能会失败”的大警告信号。CLR 确保只有有效的写入在执行时成功。例如:

string[] strings = new string[1];
object[] objects = strings;
objects[0] = new object();

ArrayTypeMismatchException这将在执行时抛出异常 ( )。另一种方法是在执行时允许它,此时strings[0]将是对非字符串对象的引用,这显然是不好的。

另请参阅最近的博客文章:

于 2013-07-12T16:05:43.993 回答
0

我想他们想说的是:

Dog dog = new Dog();
Cat[] cats = new Cat[] { catOne, catTwo, catThree };
Animal[] animals = cats;
animals.Add(dog);

此代码的第 3 行不合法,因为您应该始终能够执行第 4 行(将 a 添加Dog到 s 数组Animal)。但是如果第 3 行是合法的,那么第 4 行就不合法(因为您不能将 a 添加Dog到 s 数组中Cat)。

于 2013-07-12T16:07:24.303 回答