Как динамически создать универсальный объект C# с помощью отражения? [дубликат]
этот вопрос уже есть ответ здесь:
В C# у меня есть следующий объект:
public class Item
{ }
public class Task<T>
{ }
public class TaskA<T> : Task<T>
{ }
public class TaskB<T> : Task<T>
{ }
Я хочу динамически создавать TaskA или TaskB с помощью отражения C# (активатор.CreateInstance). Однако Я бы не знал тип перед рукой, поэтому мне нужно динамически создавать TaskA на основе строки типа "namespace.Таска "или" пространство имен.Таскаб".
5 ответов:
зацените статьи и простой пример:. Быстрый перевод же для ваших классов ...
var d1 = typeof(Task<>); Type[] typeArgs = { typeof(Item) }; var makeme = d1.MakeGenericType(typeArgs); object o = Activator.CreateInstance(makeme);На изменить: в этом случае, вы можете сделать это ...
var d1 = Type.GetType("GenericTest.TaskA`1"); // GenericTest was my namespace, add yours Type[] typeArgs = { typeof(Item) }; var makeme = d1.MakeGenericType(typeArgs); object o = Activator.CreateInstance(makeme);чтобы увидеть, где я придумал backtick1 для имени универсального класса, см. в этой статье.
Примечание: Если ваш универсальный класс принимает несколько типов, вы должны включать запятые, когда вы опускаете имена типов, для пример:
Type type = typeof(IReadOnlyDictionary<,>);
действительно, Вы не сможете написать последнюю строку.
но вы, вероятно, не хотите создавать объект, просто ради или создавая его. Вероятно, вы хотите вызвать какой-то метод на вашем вновь созданном экземпляре.
вам понадобится что-то вроде интерфейса :
public interface ITask { void Process(object o); } public class Task<T> : ITask { void ITask.Process(object o) { if(o is T) // Just to be sure, and maybe throw an exception Process(o as T); } public void Process(T o) { } }и вызовите его с помощью :
Type d1 = Type.GetType("TaskA"); //or "TaskB" Type[] typeArgs = { typeof(Item) }; Type makeme = d1.MakeGenericType(typeArgs); ITask task = Activator.CreateInstance(makeme) as ITask; // This can be Item, or any type derived from Item task.Process(new Item());в любом случае, вы не будете статически приведены к типу, который вы не знаете заранее ("makeme" в этом случае). ITask позволяет получить для вашего целевого типа.
Если это не то, что вы хотите, вы, вероятно, должны быть немного более конкретным в том, что вы пытаетесь достичь с этим.
Мне кажется, что последняя строка вашего примера кода должна быть просто:
Task<Item> itsMe = o as Task<Item>;или я что-то пропустила?
убедитесь, что вы делаете это по уважительной причине, простая функция, подобная следующей, позволит статический ввод и позволяет вашей среде IDE делать такие вещи, как "найти ссылки" и рефакторинг -> переименовать.
public Task <T> factory (String name) { Task <T> result; if (name.CompareTo ("A") == 0) { result = new TaskA (); } else if (name.CompareTo ("B") == 0) { result = new TaskB (); } return result; }
Я знаю, что этот вопрос решен, но для пользы любого другого читающего его; если у вас есть все типы, участвующие в качестве строк, вы можете сделать это как один лайнер:
IYourInterface o = (Activator.CreateInstance(Type.GetType("Namespace.TaskA`1[OtherNamespace.TypeParam]") as IYourInterface);всякий раз, когда я делал такие вещи, у меня был интерфейс, который я хотел использовать в последующем коде, поэтому я привел созданный экземпляр к интерфейсу.
Comments