2010-01-30 9 views
0

(je suis sûr que cela a été déjà répondu, je cherchais, mais n'a pas pu le trouver)Créer une instance d'un objet Type de classe générique inconnue lors de l'exécution?

Je dois créer une instance de plusieurs types génériques au cours de l'exécution. C'est, j'ai une variable nommée i qui détient un nombre compris entre 0-4, et je dois créer une instance de l'objet Type pour les deux Action<>, Action<T1>, Action<T1, T2>, Action<T1, T2, T3> ou Action<T1, T2, T3, T4> en fonction de ce que le nombre est (la le cas réel n'est pas aussi simple, de sorte qu'il est vraiment compris entre 0 et 4 et que je peux simplement utiliser une instruction switch).

Edit: Précisé que j'ai besoin de l'objet Type du type et non une instance du type.

+0

Eh bien, si vous ne pouvez pas utiliser l'interrupteur juste parce que l'interrupteur ne fonctionne que sur les constantes que vous pouvez envisager d'utiliser un si bloc autre et typeof (Action <>) –

+0

Eh bien, votre vrai problème est que vous ne pouvez pas créer une action sans connaître le type de T1. Alors connaissez-vous les paramètres de type pour chaque cas? – driis

+0

Il ne souhaite pas créer une instance de l'action , uniquement l'objet type correspondant. –

Répondre

3

La façon la plus générique que je peux penser est en chargeant le type d'action cible par nom où le nombre après la backtick (aka grave accent) représente le nombre d'arguments génériques dont vous avez besoin.

Malheureusement, Action<> se trouve dans un assemblage différent (mscorlib) par rapport aux autres types d'actions, il doit donc être traité différemment lors de l'utilisation de cette approche.

public static Type GetActionDelegateType(params Type[] typeArgs) 
{ 
    var argCount = typeArgs.Length; 
    if (argCount == 0) return typeof (Action); 
    var defType = argCount == 1 
     ? typeof (Action<>) //special case since it's found in mscorlib 
     : Type.GetType(string.Format("System.Action`{0}, {1}", 
      argCount, 
      typeof (Action).Assembly.FullName)); 
    return defType.MakeGenericType(typeArgs); 
} 

Vous pouvez voir le code ci-dessus en action en utilisant ce code de test:

for (var i = 0; i <= 4; i++) 
{ 
    var typeArgs = Enumerable.Repeat(typeof (string), i).ToArray(); 
    Console.WriteLine(GetActionDelegateType(typeArgs)); 
} 
-1

Utilisez Activator.CreateInstance(string assembly, string classname). L '"assembly" pourrait être nul (dans ce cas, rechercher dans l'assemblage en cours pour les types de classes)

Le "classname" doit représenter le nom de la classe, que vous pourriez dériver de l'entier ou de toute autre information que vous avez.

Pour les classes de modèle, utilise la forme de chaîne classif "ClassName'T1".

+0

Peut-être que j'ai mal compris vous ou moi, mais je veux une instance d'un objet ** Type **, pas un objet qui est l'instance de ce type. – thr

+0

Ops. Je t'ai mal compris. Toutefois, vous pouvez toujours appeler GetType() une fois que vous avez déplié le ObjectHandle renvoyé par CreateInstance. Pas direct, mais devrait fonctionner. – Luca

-1

Utilisez soit typeof(Action<...>) sur une classe (la méthode statique), soit la méthode GetType() sur une instance (la méthode dynamique).

+0

typeof ne fonctionnera pas sauf si je crée une instruction switch pour chaque combinaison possible, ce que j'ai dit était impossible. Et GetType() n'est pas possible non plus car je n'ai pas d'objet de ce type. – thr

0

Je ne suis pas sûr de comprendre ce que vous essayez d'accomplir. Je vais essayer de deviner.

Si vous savez que la quantité nécessaire des paramètres de type ne dépassera jamais quatre, vous pouvez simplement faire un tableau

Type[] types = new Type[] { typeof(Action<>), typeof(Action<,>), typeof(Action<,,>) }; // omitted the rest 

et fournir une fonction

int CalculateNumberOfParameters(int i) 
{  
    // I don't know what your i variable really means, but I suggest you have some method to determine a number of type parameters from it). 
} 

Ensuite, vous utilisez simplement les types [CalculateNumberOfParameters (i)] pour obtenir votre type d'action. Notez que j'ai fourni un tableau de génériques non paramétrés, donc vous devriez appeler MakeGenericType() pour créer un type instantiable réel. Si vous connaissez au préalable vos paramètres génériques (et qu'ils ne dépendent pas de i), vous devez les spécifier lors de la création du type de tableau.

Si vous ne pouvez jamais connaître la quantité de paramètres génériques dont vous aurez besoin, vous devrez créer des types lors de l'exécution, car .net ne définit que l'action avec les paramètres 0-4. Vous devrez toujours fournir une conversion (ou un adaptateur) à l'un des types standard, de sorte que les instances de votre type créé peuvent réellement être utilisables à partir d'une autre partie de votre application. C'est une route difficile, et je n'ai dû l'utiliser qu'une seule fois (pour la sérialisation de l'expression linq), donc je ne vais pas entrer dans les détails à moins d'une question spécifique.

-1

Vous ne savez pas très bien ce que vous cherchez, vous n'avez jamais mentionné d'où obtiendrez-vous T1, T2, T3?

Ce code pourrait vous être utile.

private static void CreateAppropriateAction(params Type[] argTypes) 
     { 
      var numberOfArgs = argTypes.Count(); 
      switch (numberOfArgs) 
      { 
       case 1: 
        var oneArgAction = typeof(Action<>).MakeGenericType(argTypes); 
        break; 
       case 2: 
        var twoArgAction = typeof(Action<,>).MakeGenericType(argTypes); 
        break; 
       case 3: 
        var threeArgAction = typeof(Action<,,>).MakeGenericType(argTypes); 
        break; 
       default: 
       //Do nothing or throw exception 
        break; 
      } 
     }    

Ensuite, vous pouvez utiliser cette méthode avec un appel comme celui-ci ...

CreateAppropriateAction(typeof(string),typeof(int)); 
Questions connexes