当关系应该隐式时,如何避免显式定义泛型类型参数? [英] How do I avoid explicitly defining generic type arguments when the relationship should be implicit?

查看:136
本文介绍了当关系应该隐式时,如何避免显式定义泛型类型参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究这个例子:

食物分类:

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 the Feed(T food) method. This is key.
  • The Farm class has a T FoodSupply in order to feed the Animals within it.
  • The Farm class needs to call Feed(T food) on the Animal but it can't do that without knowing what T 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(例如),其中FoodSupplyMeat-只有您不能将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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆