Comment créer dynamiquement un objet c# Générique En utilisant la réflexion? [dupliquer]

cette question a déjà une réponse ici:

dans C# j'ai l'objet suivant:

public class Item
{ }

public class Task<T>
{ }

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

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

je veux dynamiquement créer TaskA ou TaskB en utilisant C# réflexion (activateur .CreateInstance ). Cependant, je ne saurais pas le type avant main, donc je dois dynamiquement créer TaskA basé sur une chaîne de caractères comme " namespace.Taska "ou" namespace.TaskAB".

105
demandé sur Jeff 2009-07-20 05:58:03

5 réponses

découvrez ce article et de cette simple exemple . Traduction rapide de la même à vos classes ...

var d1 = typeof(Task<>);
Type[] typeArgs = { typeof(Item) };
var makeme = d1.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(makeme);

Par votre edit: Pour ce cas, vous pouvez le faire ...

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

pour voir où j'ai trouvé backtick1 pour le nom de la classe générique, voir cet article .

Note: si votre classe générique accepte plusieurs types, vous doit inclure les virgules lorsque vous omettez les noms de type, par exemple:

Type type = typeof(IReadOnlyDictionary<,>);
200
répondu JP Alioto 2015-08-05 18:24:54

en Effet, vous ne seriez pas en mesure d'écrire la dernière ligne.

mais vous ne voulez probablement pas créer l'objet, juste pour le plaisir ou la création. Probablement, vous voulez appeler une méthode sur votre instance nouvellement créée.

vous aurez alors besoin de quelque chose comme une interface:

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

et appelez-le avec:

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

dans tous les cas, vous ne serez pas statiquement moulé à un type que vous ne connaissez pas avant ("makeme" dans ce cas). ITask vous permet d'atteindre votre type de cible.

Si ce n'est pas ce que vous voulez, vous aurez probablement besoin d'être un peu plus précis dans ce que vous essayez d'atteindre avec cette.

6
répondu Jerome Laban 2009-07-20 02:49:26

il me semble que la dernière ligne de votre code d'exemple devrait simplement être:

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

ou est-ce que je rate quelque chose?

2
répondu Ben M 2009-07-20 02:35:06

assurez-vous que vous le faites pour une bonne raison, une fonction simple comme celle qui suit permettrait la saisie statique et permettrait à votre IDE de faire des choses comme" Find References " et Refactor - > Rename.

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;
}
1
répondu clemahieu 2009-07-21 22:46:46

je sais que cette question est résolue mais, pour le bénéfice de quelqu'un d'autre le lisant; si vous avez tous les types impliqués comme cordes, vous pouvez le faire comme une doublure:

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

chaque fois que j'ai fait ce genre de chose, j'ai eu une interface que je voulais utiliser avec le code suivant, donc j'ai placé l'instance créée dans une interface.

1
répondu A Aiston 2015-10-03 05:12:11