2009-02-23 7 views
37

J'ai une table dans ma base de données que j'utilise pour gérer les relations dans mon application. c'est assez basique dans sa nature - parentType, parentId, childType, childId ... tout comme ints. J'ai fait cette configuration auparavant, mais je l'ai fait avec une configuration switch/case quand j'avais 6 tables différentes que j'essayais de lier. Maintenant j'ai 30 tables que j'essaye de faire ceci avec et j'aimerais pouvoir faire ceci sans devoir écrire 30 entrées de cas dans ma commande de commutateur.Créer dynamiquement un objet de <Type>

Existe-t-il un moyen de faire référence à une classe .Net en utilisant une chaîne? Je sais que ce n'est pas valide (parce que je l'ai essayé plusieurs variantes de ce):

Type t = Type.GetType("WebCore.Models.Page"); 
object page = new t(); 

Je sais comment obtenir le type d'un objet, mais comment puis-je utiliser à la volée que pour créer un nouveau objet?

Répondre

49

Ce lien devrait aider:

http://msdn.microsoft.com/en-us/library/system.activator.createinstance(VS.71).aspx

Activator.CreateInstance va créer une instance du type spécifié.

vous pouvez envelopper que dans une méthode générique comme ceci:

public T GetInstance<T>(string type) 
{ 
    return (T)Activator.CreateInstance(Type.GetType(type)); 
} 
+2

Cela ne fonctionnera pas si l'assembly contenant le type n'est pas déjà chargé dans AppDomain. –

+3

De même, pour appeler cette méthode, l'OP doit avoir accès au type lors de la compilation - la question d'origine a demandé comment créer une instance au moment de l'exécution à partir d'une chaîne. –

+0

Je base simplement ma réponse sur l'exemple fourni dans la question. –

9

Vous voulez utiliser Activator.CreateInstance.

Voici un exemple de la façon dont cela fonctionne:

using System; 
using System.Runtime.Remoting; 

class Program 
{ 
    static void Main() 
    { 
     ObjectHandle o = Activator.CreateInstance("mscorlib.dll", "System.Int32"); 

     Int32 i = (Int32)o.Unwrap(); 
    } 
} 
11

Si le type est connu par l'appelant, il y a une meilleure façon plus rapide que d'utiliser Activator.CreateInstance: vous pouvez utiliser à la place une contrainte générique sur la méthode qui spécifie qu'il a un constructeur par défaut sans paramètre.

Cette méthode est sécurisée et ne nécessite pas de réflexion.

T CreateType<T>() where T : new() 
{ 
    return new T(); 
} 
+6

Il ne nécessite pas de réflexion au niveau du code source - il utilise cependant Activator.CreateInstance dans l'IL généré. –

+1

La réflexion est nécessaire car l'OP a spécifié une chaîne pour identifier le type. –

0

En supposant que vous avez le type:

public class Counter<T> 
{ 
    public T Value { get; set; } 
} 

et ont le nom de montage qualifié du type, vous pouvez construire de la manière suivante:

string typeName = typeof(Counter<>).AssemblyQualifiedName; 
Type t = Type.GetType(typeName); 

Counter<int> counter = 
    (Counter<int>)Activator.CreateInstance(
    t.MakeGenericType(typeof(int))); 

counter.Value++; 
Console.WriteLine(counter.Value); 
8
public static T GetInstance<T>(params object[] args) 
{ 
    return (T)Activator.CreateInstance(typeof(T), args); 
} 

J'utiliserais Activator.CreateInstance() au lieu de lancer, comme activateur h en tant que constructeur de génériques.

1

Voici une fonction que j'ai écrite qui clone un enregistrement de type T, en utilisant la réflexion. Ce est une implémentation très simple, je ne gère pas les types complexes etc.

public static T Clone<T>(T original) 
    { 
     T newObject = (T)Activator.CreateInstance(original.GetType()); 

     foreach (var prop in original.GetType().GetProperties()) 
     { 
      prop.SetValue(newObject, prop.GetValue(original)); 
     } 

     return newObject; 
    } 

J'espère que cela peut aider quelqu'un.

Assaf

Questions connexes