Вызов универсального метода с динамическим типом

Предположим, что у меня есть следующие классы

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

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

Ответ 1

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

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

Ответ 2

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

Чтобы использовать отражение, вы должны использовать Type.GetMethod, чтобы получить определение метода, затем вызовите MethodInfo.MakeGenericMethod(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 наследуются от Animal. Тогда, надеюсь, у него не будет проблем с List<animalType> animals = creator.CreateAnimals<type>(5);

Ответ 4

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

Ответ 5

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

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

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

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