为什么 C# 不将 Container<Derived> 隐式转换为 Container<Base>?

问题描述 投票:0回答:1

考虑以下代码片段:

class Animal {}
class Dog : Animal {}

interface MyContainer<T> {
    T Get(int i);
    void Add (T thing);
}

class MyList<T> : MyContainer<T> {
    private List<T> items = new List<T>();
    public T Get(int i) { return items[i]; }
    public void Add(T item) { items.Add(item); }
}


public static void Main(string[] args)
{
    MyContainer<Dog> dogs = new MyList<Dog>();

    // Why doesn't this cast dogs to animals?
    MyContainer<Animal> animals = dogs;
    animals.Add(new Animal());
    Animal retrievedAnimal = animals.Get(0);
    animals.Add(new Dog());
}

我知道上面的 C# 会失败,因为泛型是不变的。我知道

MyContainer<Animal> animals = dogs;
行将会失败,因为即使在您可能将
MyList<Dog>
称为
MyContainer<Animal>
(其中容器是协变的)的情况下,它仍然是
MyList<Dog>
并且误导性的引用可能会让用户感到困惑将
Cat
添加到
MyList<Dog>
,这就是为什么在这种情况下界面无法包含接受
T
.

的方法

我的问题是:当引用更改时,为什么编译器不简单地将

dogs
对象转换为
MyContainer<Animal>
?这对我来说是合乎逻辑的,从那时起,引用适当地指向正确类型的对象,我们可以自由地从容器中添加和删除任何
Animal
。当我们使用引用来引用作为引用类型的子集但不等于它的对象时,似乎所有类型问题都会出现。编译器不可能隐式推断出这样的转换吗?

c# generics covariance
1个回答
0
投票

如果我正确地阅读了你的问题,那么你似乎对演员阵容的实际含义存在误解。您似乎认为强制转换实际上改变了对象的类型。事实并非如此。它只是通过不同类型的引用提供对同一对象的访问。 “cast”一词与“以不同的光线投射某物”的含义相同,即以不同的方式看待同一物体。你说:

从那时起,引用适当地指向正确类型的对象,我们可以自由地从容器中添加和删除任何动物

这需要实际对象从

Container<Dog>
更改为
Container<Animal>
,因为显然除了
Dog
之外你不能添加任何东西到
Container<Dog>
。您所说的是转换,而不是强制转换,这绝对不会隐式发生。既然同一个对象仍然可以被原始类型的另一个变量引用,那怎么可能呢?

© www.soinside.com 2019 - 2024. All rights reserved.