c# - 为什么实现变体接口(interface)的类保持不变?

标签 c# c#-4.0 ienumerable covariance

C# 4.0 进一步扩展了通用类型和接口(interface)的协变和逆变。一些接口(interface)(如 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 中声明为协变或逆变无论如何,因为它有成员接受和返回 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;
    }
}

那可能仍然是无效的——变量仍然是可写的,这意味着它算作一个“输入”槽。您必须使每个变量类型为 T只读...这只是初学者。我强烈怀疑会有更深层次的问题。

就纯粹的实用主义而言,CLR 已支持 v2 中的委托(delegate)和接口(interface)变体 - C# 4 刚刚引入了语法来公开该功能。我不相信 CLR 曾经支持泛型类变体。

关于c# - 为什么实现变体接口(interface)的类保持不变?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13107071/

相关文章:

c# - 如何审核 asp.net/SQL Server 用户

c# - Skip 的性能(以及类似的功能,如 Take)

c# - 为什么我的 NAudio FFT 结果与 MATLAB 结果相差 4 倍?

c# - 从流中实例化位图时出现 ArgumentException

c#继承麻烦。我在继承链中看不到方法

c# - 带枚举的 RegularExpression 属性

c# - 如何从列表添加到数组并返回数组

c# - Linq 和 DBNull - 出现错误

c# - 在 .Net Core AppSettings/配置中处理带句点的键名

c# - 保留同一个类的列表