当关系应该隐式时,如何避免显式定义泛型类型参数? [英] How do I avoid explicitly defining generic type arguments when the relationship should be implicit?
问题描述
我正在研究这个例子:
食物分类:
public class Food { }
public class Meat : Food { }
public class Grass : Food { }
动物类:
public abstract class Animal<TFood>
where TFood : Food
{
public void Feed(TFood food) { }
}
public abstract class Carnivore : Animal<Meat> { }
public abstract class Herbivore : Animal<Grass> { }
public class Cow : Herbivore { }
农场分类:
public abstract class Farm<TAnimal, TFood>
where TAnimal : Animal<TFood>
where TFood : Food
{
public List<TAnimal> Animals;
public TFood FoodSupply;
public void FeedAnimals()
{
foreach ( var animal in Animals )
{
animal.Feed(FoodSupply);
}
}
}
public class DariyFarm : Farm<Cow, Grass> { }
我感到很烦的是,对于一个奶牛场,我必须定义食物的类型,因为食物的类型应该已经由母牛定义了.
And I found it annoying that for a dairy farm I had to define the type of food, since the type of food should already be defined by the cow.
我觉得我在这里想念什么.理想情况下,我希望能够仅根据其饲养的动物来定义一个农场,然后由该动物定义食物类型.不幸的是,您必须在未指定食物类型T的情况下将Animal约束应用于U.
I feel like I'm missing something here. Ideally, I would like to be able to define a farm only in terms of what animal it farms, and then the food type would be defined by the animal. Unfortunately, you can't apply the Animal constraint to U without specifying a food type T.
我想念什么?
推荐答案
不幸的是,这是通用类型系统在C#中的工作方式.
Unfortunately this is how the generic type system works in C#.
您有此问题,因为:
-
Animal
类具有Feed(T food)
方法.这是关键. -
Farm
类具有一个T
FoodSupply,以便在其中填充Animal
. -
Farm
类需要在Animal
上调用Feed(T food)
,但是在不知道T
是什么的情况下不能这样做.
- The
Animal
class has theFeed(T food)
method. This is key. - The
Farm
class has aT
FoodSupply in order to feed theAnimal
s within it. - The
Farm
class needs to callFeed(T food)
on theAnimal
but it can't do that without knowing whatT
is.
您可以使用界面解决此问题.假设您有一个IAnimal
界面:
You can get around this with interfaces. Say you had an IAnimal
interface:
public interface IAnimal
{
void Feed(Food food);
}
然后Animal<T>
可以实现它:
public abstract class Animal<TFood> : IAnimal where TFood : Food
{
public void Feed(TFood food)
{
// we either need to check for null here
}
public void Feed(Food food)
{
// or we need to check food is TFood here
Feed(food as TFood);
}
}
然后,您可以更改您的Farm
类以完全摆脱泛型:
Then you can change your Farm
class to get rid of the generics altogether:
public abstract class Farm<TAnimal> where TAnimal : IAnimal
{
public List<TAnimal> Animals;
public Food FoodSupply;
public void FeedAnimals()
{
foreach ( var animal in Animals )
{
animal.Feed(FoodSupply);
}
}
}
现在的问题是,您可以拥有一个DairyFarm
(例如),其中FoodSupply
是Meat
-只有您不能将Meat
喂给Cow
,因为它们只吃
The problem now is that you can have a DairyFarm
(say) for which the FoodSupply
is Meat
- only you can't feed a Meat
to a Cow
as they only eat Grass
.
您需要同时具有两个类型参数以使用泛型-编译器无法从Animal<T>
推断Food
的特定类型.
You need to have both type arguments to make use of generics - the compiler can't infer the specific type of Food
from the Animal<T>
.
这篇关于当关系应该隐式时,如何避免显式定义泛型类型参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!