I work as a developer for few years but seems like I still do not understand some advanced stuff about generics.
I've prepared some self explanatory piece of code:
public enum AnimalType { Cat, Dog}
public interface IAnimal { }
public class Dog : IAnimal { }
public class Cat : IAnimal { }
public interface IAnimalHandler<in TAnimal> where TAnimal : IAnimal { void Handle(TAnimal animal); }
public class CatHandler : IAnimalHandler<Cat>
{
public void Handle(Cat animal) { }
}
public class DogHandler : IAnimalHandler<Dog>
{
public void Handle(Dog animal) { }
}
public class AnimalFactory
{
public IAnimal GetAnimal(AnimalType type) { return type == AnimalType.Cat ? (IAnimal) new Cat() : (IAnimal)new Dog();}
}
public class AnimalHandlerFactory
{
public IAnimalHandler<TAnimal> GetAnimalHandler<TAnimal>(TAnimal animal) where TAnimal : IAnimal
{
switch (animal)
{
case Cat cat:
return new CatHandler() as IAnimalHandler<TAnimal>;
case Dog dog:
return new CatHandler() as IAnimalHandler<TAnimal>;
default:
throw new Exception();
}
}
}
public class FactoryTests
{
[Fact]
public async Task factory_returns_concrete()
{
var myAnimal = new AnimalFactory().GetAnimal(AnimalType.Dog);
var handlerForMyAnimal = new AnimalHandlerFactory().GetAnimalHandler(myAnimal);
Assert.NotNull(handlerForMyAnimal);
}
}
And now, coud you please answer to my doubts?
1) Why do I have to perform casting in GetAnimalHandler() method?
2) Test is failing because AnimalFactory returns an abstraction object (declaration) and this type is used as generic type of GetAnimalHandler() method so obviously casting returned null. The question is how to solve this problem? Am I missing some pattern?