Why can't I use a list of functions returning a generic class with different type parameters in C#

47 Views Asked by At

I'm working on a C# project where I have an interface IAnimal and two classes Dog and Cat that implement this interface. I also have a generic class Zoo<T> where T is a type that implements IAnimal.

Here's the relevant code:

public interface IAnimal { /* ... */ }

public class Dog : IAnimal { /* ... */ }

public class Cat : IAnimal { /* ... */ }

public class Zoo<T> where T : IAnimal { /* ... */ }

I'm trying to create two functions CreateZooOfDog and CreateZooOfCat that return a Zoo<Dog> and Zoo<Cat> respectively. I then want to add these functions to a list and call them in a loop. Here's what I tried:

public Zoo<Dog> CreateZooOfDog() { /* ... */ }

public Zoo<Cat> CreateZooOfCat() { /* ... */ }

var zooes = new List<Func<Zoo<IAnimal>>>();

Func<Zoo<Dog>> zooOfDog = () => program.CreateZooOfDog();
Func<Zoo<Cat>> zooOfCat = () => program.CreateZooOfCat();

zooes.Add(zooOfDog);
zooes.Add(zooOfCat );

However, I'm getting a compile-time error on the CreateZooOfDog and CreateZooOfCat " .

enter image description here

I don't understand why this is happening since Dog and Cat both implement IAnimal. Could someone explain why this is happening and how I can fix it?"

If i modify the list to List, then i can add both Cat/Or to the List.

enter image description here

1

There are 1 best solutions below

1
jaabh On

The point of generics is so multiple methods do not need to be created in order to return a type T. Having a specific method that accepts an IAnimal but returns only a Dog type, then one more for returning a Cat type defeats the purpose of using generics.

It would make more sense to have a single method that accepts type IAnimal determines the type that needs to be returned and return it.

public interface IAnimal {  }

public class Dog : IAnimal {  }

public class Cat : IAnimal {  }

public class Zoo<T> where T : IAnimal {  }
public Zoo<T> CreateZoo<T>(T animal)
{
    //Determine type T that needs to be returned 
    if (animal is Cat)
        //
    if (animal is Dog)
        //
}

Then just cast to whichever type is needed.

Dog dog = (Dog)zooObj.CreateZoo(new Dog());
Cat cat = (Cat)zooObj.CreateZoo(new Cat());

This would be a better use of generics and reduce multiple functions that effectively do the same thing. Other functions that are specific to Dog, or specific to Cat could be private and once the CreateZoo function determines the type that is needed to be returned, can rely on those private encapsulated methods.