How do I avoid explicitly defining generic type arguments when the relationship should be implicit?

前端 未结 2 1905
面向向阳花
面向向阳花 2021-01-28 16:39

I was working on this example:

Food classes:

public class Food { }

public class Meat : Food { }

public class Grass : Food { }

Animal

2条回答
  •  难免孤独
    2021-01-28 17:32

    Unfortunately this is how the generic type system works in C#.

    You have this problem because:

    • 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.

    You can get around this with interfaces. Say you had an IAnimal interface:

    public interface IAnimal
    {
        void Feed(Food food);
    }
    

    then Animal could implement it:

    public abstract class Animal : 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);
        }
    }
    

    Then you can change your Farm class to get rid of the generics altogether:

    public abstract class Farm where TAnimal : IAnimal
    {
        public List Animals;
    
        public Food FoodSupply;
    
        public void FeedAnimals()
        {
            foreach ( var animal in Animals )
            {
                animal.Feed(FoodSupply);
            }
        }
    }
    

    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.

    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.

提交回复
热议问题