Как динамически создать универсальный объект C # с помощью отражения? [Дубликат]

This question already has an answer here:

Pass An Instantiated System.Type as a Type Parameter for a Generic Class 5 answers

В C # у меня есть следующий объект:

public class Item
{ }

public class Task<T>
{ }

public class TaskA<T> : Task<T>
{ }

public class TaskB<T> : Task<T>
{ }

Я хочу динамически создавать TaskA или TaskB с помощью отражения C # (Activator.CreateInstance). Однако я бы не знал тип заранее, поэтому мне нужно динамически создавать TaskA на основе строки типа & quot; namespace.TaskA & quot; или "namespace.TaskAB".

Ответы на вопрос(5)

На самом деле вы не сможете написать последнюю строку.

Но вы, вероятно, не хотите создавать объект, просто ради или создавая его. Вы, вероятно, хотите вызвать какой-то метод для только что созданного вами экземпляра.

Затем вам понадобится что-то вроде интерфейса:

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 позволяет вам добраться до вашего целевого типа.

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

 Jeff20 июл. 2009 г., 05:06
У меня есть что-то вроде Process () в Task & lt; T & gt ;. И в моем случае я на самом деле больше не беспокоюсь о последней строке, поскольку вы заявили, что я просто вызываю task.Process (), поэтому возможность кодирования последней строки становится неуважительной.

Я знаю, что этот вопрос решен, но в интересах всех, кто его читает; если у вас есть все типы, задействованные в виде строк, вы можете сделать это как один слой:

IYourInterface o = (Activator.CreateInstance(Type.GetType("Namespace.TaskA`1[OtherNamespace.TypeParam]") as IYourInterface);

Всякий раз, когда я делал подобные вещи, у меня был интерфейс, который я хотел использовать в последующем коде, поэтому я приводил созданный экземпляр к интерфейсу.

Решение Вопроса

Проверьте этостатья и этопростой пример, Быстрый перевод же на ваши занятия ...

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<,>);
 04 апр. 2013 г., 15:18
как сравнить общий тип, используяis ключевое слово?
 03 мар. 2011 г., 08:01
Требуется ли обратный удар, то есть, если он опущен, компилятор предполагает, что он равен 1?
 30 янв. 2018 г., 12:08
Вы также можете использовать Activator.CreateInstance & lt; T & gt; что может исключить необходимость создавать указание «typeargs» и сделайте общий тип самостоятельно.
 16 мая 2011 г., 20:48
Спасибо за ссылку на мою статью в блоге "Использование отражения для создания общего класса в C # .Net" (omegacoder.com/?p=38) в качестве «простого примера». :-) Я рад, что статья обретает новую жизнь.

Мне кажется, что последняя строка вашего примера кода должна быть просто:

Task<Item> itsMe = o as Task<Item>;

Или я что-то упустил?

 Jeff20 июл. 2009 г., 04:41
Вы ничего не упускаете. Это я, кто не думал прямо. Я не должен был пить столько алкоголя в последний вечер!

Убедитесь, что вы делаете это по уважительной причине. Простая функция, подобная следующей, разрешает статическую типизацию и позволяет вашей IDE выполнять такие действия, как & quot; Поиск ссылок & quot; и Refactor - & gt; Переименовать.

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;
}
 22 июл. 2009 г., 00:59
Почему вы используете .CompareTo? Почему бы не == или .Equals (если вы хотите больше контроля). Может быть, переключатель будет даже лучше.
 22 июл. 2009 г., 01:29
Я никогда не проверял, выполняет ли C # сравнение строк на == вместо сравнения ссылок. CompareTo и Equals должны иметь одинаковую эффективность времени выполнения, если они были реализованы правильно. Блок переключателей не будет иметь таких же ускорений, как и помещение целого числа в блок переключателей; он будет компилироваться в блок if-else.

Ваш ответ на вопрос