2010-11-04 6 views
33

Допустим, у меня есть следующие классыВызов шаблонный метод с динамическим типом

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 
    } 
} 

Теперь в некотором коде позже я хочу, чтобы прочитать в том, что животное, чтобы создать.

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); 

Теперь проблема в последней строке недействительна. Есть ли какой-то элегантный способ сделать это?

+2

Generics на самом деле не путь сюда, вы должны просто создать список и использовать Activator для создания производных классов. – Doggett

ответ

18

Не совсем. Вы должны использовать отражение, в основном. Дженерики действительно нацелены на статические, а не на типы, известные только во время выполнения.

Чтобы использовать отражение, вы должны использовать Type.GetMethod, чтобы получить определение метода, затем вызовите MethodInfo.MakeGenericMethod(type), а затем вызовите его, как и любой другой метод.

46

Я не знаю о элегантно, но способ сделать это:

typeof(Creator) 
    .GetMethod("CreateAnimals") 
    .MakeGenericMethod(type) 
    .Invoke(creator, new object[] { 5 }); 
+2

Хотя вы не сможете использовать его как «Список » или «Список ' и т. Д., Если вы уже не знаете тип во время компиляции, которого у вас нет. Лучшее, что вы можете сделать, это нажать на 'IList'. – LukeH

+0

@ LukeH, правый, хорошо пункт. –

+0

Это так уродливо, но это правильный ответ. – tofutim

1

Клавиши этого являются MakeGenericType() и MakeGenericMethod(). После того, как вы стали динамичными с типами, вы не можете вернуться к статическому набору текста. То, что вы можете сделать, это создать список динамически, используя Activator.CreateInstance(typeof(List<>).MakeGenericType(type)), а затем динамически вызывать общий метод с использованием аналогичных рефлексивных методов.

3

Попробуйте это:

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 
} 

Он должен убедиться, что разрешенные типы для CreateAnimals наследуют от животных. Тогда, надеюсь, это не будет иметь проблемы с List<animalType> animals = creator.CreateAnimals<type>(5);

+0

Это не помогает, если OP хочет прочитать, какой тип животных создать из строки. –

0
List<animalType> animals = 
creator.CreateAnimals<type>(5); 

В приведенной выше строки из вашего примера, animalType и type запускаются временные переменные, а не типы, так что это, конечно, нонсенс. Обобщенный вариант имеет смысл только, если вы знаете типы во время компиляции, например .:

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

, где вы должны соответствующим образом тягот типов. Если типы неизвестны, вам нужно полностью полагаться на отражение ...

Смежные вопросы