c# – 为什么实现变体接口的类保持不变?

C#4.0扩展了通用类型和接口的协同和逆向.一些界面(如IEnumerable< T>)是协变量,所以我可以做如下事情:
IEnumerable<object> ie = new List<string>();

但这条线呢?我有一个编译时错误

List<Object> list = new List<String>();
//Cannot implicitly convert type List<string>' to List<object>'

我的意思是,如果List< T>实现IEnumerable< T>为什么List< T>还是不变的?在那里有一个很好的反例,解释为什么这不应该被允许在C#?

解决方法

首先,C#中的类总是不变的.你不能这样声明一个类:
// Invalid
public class Foo<out T>

其次 – 更重要的是你给出的例子 – List< 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中的唯一值应为null或引用香蕉或子类的实例.

现在,为什么即使在逻辑上,类也不能是协变的…我认为在实现层面上引入了问题,在编程层面上也是非常严格的限制.例如,考虑一下:

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类型的每个变量都是只读的,而且这只是初学者.我强烈怀疑会有更深层次的问题.

在纯实用主义方面,CLR已经支持v2 – C#4中的委托和接口方差,刚刚引入了公开功能的语法.我不相信CLR曾经支持泛型类差异.

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...