5

鉴于以下代码:

class Animal
{ }

class Dog : Animal
{ }

class Cage<T>
{
    private T animal;

    public Cage(T animal)
    {
        this.animal = animal;
    }

    public T Animal
    { 
        get { return animal;} 
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dog dog = new Dog();
        Cage<Animal> animalCage = new Cage<Animal>(dog);
        Cage<Dog> dogCage = (Cage<Dog>)animalCage;
    }
}

如何解决最后一个编译器错误(从 animalCage 转换为 dogCage)?

在我的代码中,我知道笼子里有一只狗,但我无法找到一种方法来施放它。我是创建转换器并从Cage<Animal>的值创建新的Cage<Dog>实例的独特替代方案吗?

4

3 回答 3

4

问题#1:你不能把一个Cage<Animal>实例变成一个Cage<Dog>实例,你需要一个Cage<Dog>实例(或更具体类型的实例),它的引用存储在一个不太具体类型的变量中。

改变

Cage<Animal> animalCage = new Cage<Animal>(dog);
Cage<Dog> dogCage = (Cage<Dog>)animalCage;

Cage<Animal> animalCage = new Cage<Dog>(dog);
Cage<Dog> dogCage = (Cage<Dog>)animalCage;

问题 #2:您不能将Cage<Dog>实例的引用存储在Cage<Animal>变量中,因为类不支持协变/逆变。

改变

class Cage<T>
{
    ...

interface ICage<out T> 
{
    T Animal { get; }
}

class Cage<T> : ICage<T> 
{

Cage<Animal> animalCage = new Cage<Dog>(dog);
Cage<Dog> dogCage = (Cage<Dog>)animalCage;

ICage<Animal> animalCage = new Cage<Dog>(dog);
ICage<Dog> dogCage = (Cage<Dog>)animalCage;

然后它工作。(如果您不更改new Cage<Animal>new Cage<Dog>,则会在运行时获得强制转换异常。)

于 2012-10-26T23:04:46.513 回答
2

这将是通用方差的工作,除了T通常应该是协变的(因为它是输出)并且您试图以逆变方式使用它。此外,方差不适用于类,仅适用于接口和委托,因此您需要定义一个ICage<T>.

协方差将允许在另一个方向进行转换:您可以ICage<Dog>转换为ICage<Animal>. 逆变会导致矛盾,因为您可以尝试将Cage<Animal>包含 a的 a 强制转换Cat为 a Cage<Dog>,从而导致get_Animal类型错误。

数组也是协变的:您可以将 aDog[]转换为 an Animal[],但不能将 anAnimal[]转换为 a ,Dog[]即使您知道它只包含狗。

我想到的下一件事是定义一个显式转换运算符,但这些不能是通用的。

最后,您需要构建一个新Cage<Dog>的来完成这项工作。

于 2012-10-26T22:59:41.867 回答
0

您可以添加通用约束

class Cage<T> where T : Animal

然后从您的方法返回基类

public Animal Animal
{ 
    get { return animal;} 
}

泛型约束通知编译器可以为T提供的类型存在限制。如果你提供其他东西,例如Cage<object>,你会得到一个编译时错误。

于 2012-10-26T22:52:59.927 回答