首先,类在 C# 中总是不变。你不能像这样声明一个类:
// Invalid
public class Foo<out T>
其次-对于您给出的示例更重要的是-无论如何,List<T> 不能在T 中声明为协变或逆变,因为它具有接受和返回类型为T 的值的成员。
想象一下,如果它是协变的。然后你可以写这个(对于明显的Fruit 类层次结构):
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];
你希望最后一行做什么?从根本上说,您不应该将Apple 引用添加到实际执行时间类型为List<Banana> 的对象。如果你把一个苹果加到一堆香蕉里,它就会掉下来。相信我,我已经试过了。
最后一行应该在类型方面是安全的 - List<Banana> 中的唯一值应该是 null 或对 Banana 实例或子类的引用。
现在至于为什么类不能是协变的,即使它们可以逻辑上......我相信这会在实现级别引入问题,并且也会非常 在编程层面也有限制。例如,考虑一下:
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;
}
}
这仍然可能是无效的——变量仍然是可写的,这意味着它被视为一个“in”槽。您必须将T 类型的每个变量都设为只读...这只是初学者。我强烈怀疑会有更深层次的问题。
就纯粹的实用主义而言,CLR 从 v2 开始支持委托和接口变化 - C# 4 只是引入了公开该功能的语法。我不相信 CLR 曾经支持泛型类变体。