为什么要实现变型接口的类保持不变? [英] Why classes that implement variant interfaces remain invariant?
问题描述
C#4.0扩展了合作和逆变进一步泛型类型和接口。某些接口(如的IEnumerable< T>
)是协变量,所以我可以做这样的事情:
C# 4.0 has extended the co and contravariance further for generic types and interfaces. Some interfaces (like IEnumerable<T>
) are covariants, so I can do things like:
IEnumerable<object> ie = new List<string>();
但对于这条线?我有一个编译时错误
but what about this line? I got a compile-time error
List<Object> list = new List<String>();
//Cannot implicitly convert type List<string>' to List<object>'
我的意思是,如果列表&LT; T&GT;
实施的IEnumerable&LT; T&GT;
为什么名单,LT ; T&GT;
仍是不变的?就是在那里,解释为什么这应该不是在C#允许一个很好的反例?
I mean, if List<T>
implement IEnumerable<T>
why List<T>
is still invariant? Is out there a good counterexample that explain why this should not be allowed in C#?
推荐答案
首先,类的总是的不变性在C#。你不能声明一个类是这样的:
Firstly, classes are always invariant in C#. You can't declare a class like this:
// Invalid
public class Foo<out T>
二 - 更重要的是你给的例子 - 列表&LT; T&GT;
不能被宣布为协变或逆变ŧ
无论如何,因为它的成员都接受和返回类型的值 T
。
Secondly - and more importantly for the example you've given - List<T>
couldn't be declared to be covariant or contravariant in T
anyway, as it has members both accepting and returning values of type T
.
试想一下,如果它的是的协变。然后,你可以写这个(为明显的水果
类层次结构):
Imagine if it were covariant. Then you could write this (for the obvious Fruit
class hierarchy):
List<Banana> bunchOfBananas = new List<Banana>();
// This would be valid if List<T> were covariant in T
List<Fruit> fruitBowl = bunchOfBananas;
fruitBowl.Add(new Apple());
Banana banana = bunchOfBananas[0];
你所期望的最后一行呢?从根本上说,你不应该能够将苹果
引用添加到一个对象,其实际执行时类型列表&LT;香蕉&GT;
。如果添加一个苹果一串香蕉,它脱落。相信我,我试过。
What would you expect that last line to do? Fundamentally, you shouldn't be able to add an Apple
reference to an object whose actual execution-time type is List<Banana>
. If you add an apple to a bunch of bananas, it falls off. Believe me, I've tried.
最后一行的 的应该是在类型方面安全 - 一个列表与LT中唯一的值;香蕉&GT;
应空
或 香蕉的实例或子类的引用。
The last line should be safe in terms of types - the only values within a List<Banana>
should be null
or references to instances of Banana
or a subclass.
现在至于为什么类不能被协变,即使他们可能的逻辑的是...我认为,引入在执行层面的问题,也将是的非常限制性的编程水平以及。例如,考虑一下:
Now as for why classes can't be covariant even when they could logically be... I believe that introduces problems at the implementation level, and would also be very restrictive at the programming level as well. For example, consider this:
public class Foo<out T> // Imagine if this were valid
{
private T value;
public T Value { get { return value; } }
public Foo(T value)
{
this.value = value;
}
}
这仍可能有无效 - 变量仍是可写的,这意味着它算作一个中插槽。你必须做类型的每个变量 T
...只读,这还只是个开始。我强烈怀疑会有更深层次的问题。
That would still probably have to be invalid - the variable is still writable, meaning it counts as an "in" slot. You'd have to make every variable of type T
read-only... and that's just for starters. I strongly suspect that there would be deeper problems.
在纯实用主义方面,CLR已经支持委托和接口方差V2 - C#4刚刚推出的语法揭露功能。我不相信CLR曾经支持泛型类方差。
In terms of pure pragmatism, the CLR has supported delegate and interface variance from v2 - C# 4 just introduced the syntax to expose the feature. I don't believe the CLR has ever supported generic class variance.
这篇关于为什么要实现变型接口的类保持不变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!