Ответ 1
Я не знаю об элегантности, но способ сделать это:
typeof(Creator)
.GetMethod("CreateAnimals")
.MakeGenericMethod(type)
.Invoke(creator, new object[] { 5 });
Предположим, что у меня есть следующие классы
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);
Теперь проблема в последней строке недействительна. Есть ли какой-то элегантный способ сделать это?
Я не знаю об элегантности, но способ сделать это:
typeof(Creator)
.GetMethod("CreateAnimals")
.MakeGenericMethod(type)
.Invoke(creator, new object[] { 5 });
Не совсем. Вы должны использовать отражение, в основном. Generics действительно нацелены на статическую типизацию, а не на типы, известные только во время выполнения.
Чтобы использовать отражение, вы должны использовать Type.GetMethod
, чтобы получить определение метода, затем вызовите MethodInfo.MakeGenericMethod(type)
, затем вызовите его как любой другой метод.
Попробуйте следующее:
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);
Ключами к этому являются MakeGenericType() и MakeGenericMethod(). После того, как вы стали динамичными с типами, вы не можете вернуться к статическому набору текста. То, что вы можете сделать, - это создать список динамически, используя Activator.CreateInstance(typeof(List<>).MakeGenericType(type))
, а затем динамически вызывать общий метод с использованием аналогичных рефлексивных методов.
List<animalType> animals =
creator.CreateAnimals<type>(5);
В приведенной выше строке из вашего примера animalType
и type
указаны переменные времени выполнения, а не типы, поэтому это, конечно, нонсенс. Общая версия имеет смысл, если вы знаете типы во время компиляции, например:
List<Animal> animals =
creator.CreateAnimals<Cow>(5);
где вам необходимо соответствующим образом ограничить типы. Если типы неизвестны, вам нужно полностью полагаться на отражение...