C#中的协变性与逆变性, Part Two: 数组协变性

来源:互联网 发布:sizeof 数组 编辑:程序博客网 时间:2024/05/19 04:56

C#用两种方式实现了可变性。今天,我们讲讲有缺陷的那种方法。

自从C# 1.0,存储引用类型元素的Array是可变的。所以下面的代码是合法的:

Animal[] animals = new Griaffe[10];

因为Giraffe要比Animal小,并且“生成某种类型的Array”是协变操作,Giraffe[]比Aniaml[]小,所以实例可以被赋予那个变量。

很不幸,在这种类型的可变性是有缺陷的。因为Java可以这么做,CLR的设计者想要支持像Java一样的语言,所以它被添加到CLR中。又因为它存在于CLR中,所以我们紧接着把它加到C#里面。这个决定在当时很有争议,我对此不满,但是我们也阻止不了。

为什么这是有缺陷的?因为把Turtle添加到Animals Arrarys应该总是合法的。但是因为数组的协变性和运行时的协变性,你不能保证一个Turtle可以被添加到Animals数据中,因为这个Animals数组的实例可能是Giraffes。(就像上面说的)

这意味着我们把一个本可以被编译器捕获的Bug变成了只能在运行时被捕获的Bug。这也意味着每次你向数组添加一个对象,我们必须执行一次运行时检查来保证类型匹配,或者在类型不匹配的时候抛出异常。如过你想数组中添加了很多这样的东西,那么代价是非常昂贵的。

不幸的是。。我们还要忍受这个。。(是的,我试了一下。。)

我想要借着这个机会阐述Part One中出现的一些观点。

首先,通过“子类”和“父类”,我想表达的意思是,“它们位于基类的继承链上”。我没有表达“可以替换的”这个概念。通过“大于”和“小于”,我特意不想表达“子类”和“基类”的意思。的确,子类是比父类都小,但小的类不一定是大的类的子类。Giraffe[]比Animal[]和System.Array都小,很明显Giraffe[]是System.Array的子类,但**不是**Animal[]的子类。因此,“更小”这种关系比“是一个”这种关系更宽泛。我想要区分一下赋值兼容性和继承。

下次我们将讨论C#2.0中可靠的可变性。

0 0
原创粉丝点击