72

Lets say I have the following classes

public class Animal { .... }

public class Duck : Animal { ... }

public class Cow : Animal { ... }

public class Creator
{
   public List<T> CreateAnimals<T>(int numAnimals)
   {
      Type type = typeof(T);
      List<T> returnList = new List<T>();
      //Use reflection to populate list and return
   }
}

Now in some code later I want to read in what animal to create.

Creator creator = new Creator();
string animalType = //read from a file what animal (duck, cow) to create
Type type = Type.GetType(animalType);
List<animalType> animals = creator.CreateAnimals<type>(5);

Now the problem is the last line isn't valid. Is there some elegant way to do this then?

cmptrer
  • 1,419
  • 4
  • 13
  • 25
  • 3
    Generics aren't really the way to go here, you should just create a List instead and use Activator to create the derived classes. – Doggett Nov 04 '10 at 22:24

5 Answers5

88

I don't know about elegant, but the way to do it is:

typeof(Creator)
    .GetMethod("CreateAnimals")
    .MakeGenericMethod(type)
    .Invoke(creator, new object[] { 5 });
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
  • 5
    Though you won't be able to cast it as `List` or `List` etc unless you already know the type at compile-time, which you don't. The best you can do is cast to `IList`. – LukeH Nov 04 '10 at 22:05
35

Not really. You need to use reflection, basically. Generics are really aimed at static typing rather than types only known at execution time.

To use reflection, you'd use Type.GetMethod to get the method definition, then call MethodInfo.MakeGenericMethod(type), then invoke it like any other method.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
5

Try this:

public List<T> CreateAnimals<T>(int numAnimals) where T : Animal
{
    Type type = typeof(T);
    List<T> returnList = new List<T>();
    //Use reflection to populate list and return
}

It should make sure that the allowed types for CreateAnimals inherit from Animal. Then hopefully, it won't have a problem with List<animalType> animals = creator.CreateAnimals<type>(5);

Samuel
  • 16,923
  • 6
  • 62
  • 75
2

The keys to this are MakeGenericType() and MakeGenericMethod(). Once you've gone dynamic with the types, you can't really go back to static typing. What you CAN do is create the list dynamically, by using Activator.CreateInstance(typeof(List<>).MakeGenericType(type)) and then dynamically calling the generic method using similar reflective methods.

KeithS
  • 70,210
  • 21
  • 112
  • 164
0
List<animalType> animals = 
 creator.CreateAnimals<type>(5);

In the above line from your example, animalType and type are run time variables, not types, so this is of course nonsense. A generic version only makes sense, if you know the types at compile time, e.g.:

List<Animal> animals = 
  creator.CreateAnimals<Cow>(5);

where you'd have to constraint types accordingly. If the types are not known, you have to rely completely on reflection...

Paul Michalik
  • 4,331
  • 16
  • 18