泛型中的协方差:用有界通配符创建泛型列表



我整天都在寻找合适的解决方案,但我对C#还很陌生。如果我是对的,想要一些类似于Java代码的东西

ArrayList<IAnimalStuff<? extends Animal>> ianimals = new ArrayList<>();

仅针对C#。或者当我走错路的时候另一种解决方案。

详细场景:我有一个基类(Animal)和多个子类(例如Dog)。

class Animal
{
}
class Dog : Animal
{
}

我创建了一个所有动物的通用列表,其中包含各种不同动物的对象。

List<Animal> animals = new List<Animal>();
animals.add(new Dog()); // and so on

此外,我还有一个接口和一个类,用于从这个接口派生的每种特殊动物。

interface IAnimalStuff<TAnimal> where TAnimal : Animal
{
void doSomething(TAnimal animal);
}
public class DogStuff : IAnimalStuff<Dog>
{
public override void doSomething(Dog animal) 
{
}
}

现在我想用Animals和AnimalStuff管理一个列表。当循环所有动物时,我想执行其他列表中对狗有效的所有Animalstuff。虽然动物列表没有问题,但我有创建另一个列表的问题。

List<IAnimalStuff<Animals>> ianimals = new List<IAnimalStuff<Animals>>();

与第一个列表不同,我只能将对象添加到类型的列表中

IAnimalStuff<Animals>

,但我也想做

ianimals.add(GetDogStuff()); // add object of type IAnimalStuff<Dog>

我认为这是有效的,因为狗是动物的一个子类。我认为用Java代码的上层可以解决这个问题,但我没有找到任何C#的解决方案。还是我走错了路?

C#有声明站点差异,而不是像Java那样使用站点差异。

在C#中,你可以这样做:

interface IAnimalStuff<in TAnimal> where TAnimal : Animal // note "in"
{
void doSomething(TAnimal animal);
}

然后你可以说

IAnimalStuff<Mammal> iasm = new MammalStuff();
IAnimalStuff<Dog> iasd = iasm;

为什么这样做?因为iasm.doSomething可以带走任何哺乳动物,而iasd.doSomething只能通过狗,而狗是哺乳动物。请注意,这是一个逆变式转换。

但你不能走另一条路;你不能说"狗是哺乳动物,所以狗是哺乳动物"。哺乳动物可以接受长颈鹿,但狗却不能。这将是一个协变转换。

我认为问题可能出现在您的列表声明中:

List<IAnimalStuff<Animals>> ianimals = new List<IAnimalStuff<Animals>>();

这是将AnimalStuff的"animal"铸造为"animal"类型。相反,请尝试使用Interface作为基础IAnimal,并将集合定义为IAnimalStuff<IAnimals>。然后让DogIAnimal继承,它应该可以实现您想要的。

相关内容

  • 没有找到相关文章

最新更新