微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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曾经支持泛型类差异.

原文地址:https://www.jb51.cc/csharp/93912.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐