假设我有一个父类Animal
,其子类为Cat
和Dog
。我还有一个Building<T>
,其中T可以是Animal
。
public class<T> Building
{
public T Inhabitant {get; set;}
}
现在,我想创建一些有猫的建筑物和一些有狗的建筑物(基于仅在运行时可用的参数)。为此,我正在尝试创建以下方法:
private Building<Animal> populateBuilding(string animalKind)
{
if(animalKind == "cat")
{
return new Building<Cat>;
}
if(animalKind == "dog")
{
return new Building<Dog>;
}
return null;
}
但是,我不能这样做,因为编译器告诉Building<Dog>/Building<Cat>
无法转换为Building<Animal>
。我找到了几个示例,其中描述了类似的问题,但使用了列表(例如List<Animal>, List<Dog>, List<Cat>
)。但是,我不会在我的情况下使用列表,并想知道它是否仍然是相同的情况。
答案 0 :(得分:3)
您应该阅读一些关于协方差和逆变的文章,例如this one。
在你的情况下,类Building
的设计是不允许的。
假设允许共同使用Building
。然后它将允许以下代码片段:
var dogHouse = new Building<Dog>();
var house = (Building<Animal>) dogHouse; // Casting to base class
house.Inhabitant = new Cat(); // Inhabitant of a Building<Animal> is any Animal
dogHouse.Inhabitant.Bark(); // Meow!
如果泛型的方法仅返回类型T
的值(作为返回值或T
- 参数),则可以与其类型参数out
协同使用泛型。如果泛型仅接受类型T
的值作为参数,则可以与其类型参数T
协同使用泛型。在您的情况下,有两个,即get_Inhabitant
返回Animal
而set_Inhabitant
接受Animal
。
此外,在C#中,正如评论中正确指出的那样,协方差和逆变的概念仅适用于接口和代理。
答案 1 :(得分:0)
您应该能够按照以下方式执行此操作:
private Building<Animal> populateBuilding(string animalKind)
{
var building = new Building<Animal>();
if (animalKind == "cat")
{
return new Building<Animal>
{
Inhabitant = new Cat()
};
}
if (animalKind == "dog")
{
return new Building<Animal>
{
Inhabitant = new Dog()
};
}
return null;
}