c#中的协变性与逆变性,Part Three:方法组转换的可变性

来源:互联网 发布:中国微观数据库 编辑:程序博客网 时间:2024/05/21 11:45

上一次我讨论了C#中的数组协变性如何会产生Bug(Java也是,还有很多其他语言)今天,我们讲讲一个C#2.0提供的健壮的可变性:从方法组到委托的转换。这是一种更复杂的可变性,所以我需要仔细地讲讲。

假设你有一个方法返回Giraffe:

static Giraffe MakeGiraffe() {...

再假设你有一个委托类型,代表一个不接受参数并返回一个Animal的函数。比如,Func,下面的隐式转换应该合法吗?

Func<Animal> func = MakeGiraffe;

func的调用者希望返回一个Animal,实际的函数总是返回Giraffe,Giraffe也是一个Animal,所以func的调用者总能获得它们想要的东西。这个隐式转换没毛病。因此,我们可以让从函数组到委托的转换的返回类型是协变的

现在假设你有两个函数,其中一个接受Giraffe参数,另一个接受Animal参数:

void Foo(Giraffe g) {}void Bar(Animal a) {}

和一个委托,委托匹配返回void接受Mammal参数的函数。

Action<Mammal> action1 = Foo; //illegalAction<Mammal> action2 = Bar; //legal

为什么第一个赋值是非法的?因为action1的调用者可以传递一个Tiger,但是Foo不能接受的一个Tiger,只能接受Giraffe!第二个赋值是合法的因为Bar可以接受任何Animal。

在我们前一个例子中,我们保留了可赋值性的方向( the direction of the assignability,不知道怎么翻译。。),Giraffe小于Animal,所以一个返回Giraffe的方法小于返回Animal的委托。在这个例子中我们反转了可赋值性的方向;Mammal比Animal要小,所以一个接受Animal的方法比接受一个Mammal的委托要小,因为方向被翻转了,函数组到委托的转换对于参数类型是逆变的

注意上述所说的都只适用于引用类型,我们从来不会说这样的话“每个int都可以转换为long,所以一个返回int的函数可以赋值给Func变量”。

下一次:更强的委托可变性。


是的,我之前说过可变性是基于类型的操作的属性,然后我现在有一个基于方法组的操作,在C#中和类型无关。我在写博客,不是写论文,你懂的。

0 0