2010-02-11 3 views
48

J'ai une classe abstraite et je veux l'initier à une classe qui l'étend. J'ai le nom des classes enfant sous la forme d'une chaîne.C# instancier la classe à partir de la chaîne

En outre ...

String childClassString; 
MyAbstractClass myObject; 

if (childClassString = "myExtenedObjectA") 
    myObject = new ExtenedObjectA(); 
if (childClassString = "myExtenedObjectB") 
    myObject = new ExtenedObjectB(); 

Comment puis-je faire cela? Fondamentalement, comment puis-je me débarrasser des déclarations si ici?

+1

Pourquoi avez-vous besoin d'instancier votre classe avec une chaîne? Selon votre cas, il pourrait y avoir des solutions «plus propres», surtout si vous n'êtes pas réticent à utiliser la réflexion. –

+1

@SylvestreEquy mais peut-être dans les cas de quelqu'un d'autre, c'est juste la solution ... Les questions sur SO ne servent pas seulement ceux qui leur demandent. –

Répondre

90

Regardez Activator.CreateInstance().

myObject = (MyAbstractClass)Activator.CreateInstance("AssemblyName", "TypeName"); 

ou

var type = Type.GetType("MyFullyQualifiedTypeName"); 
var myObject = (MyAbstractClass)Activator.CreateInstance(type); 
+6

A travaillé comme un charme. Au cas où quelqu'un aurait des problèmes pour obtenir le nom complet, ce morceau de code est utile 'string typex = typeof (classname) .AssemblyQualifiedName; –

+0

Même si la documentation de 'GetType' pour son paramètre' typeName' indique "Le nom qualifié de l'assembly du type", il n'est pas nécessaire d'inclure le nom de l'assembly. Si le type est dans l'assembly appelant, seul le nom de type qualifié d'espace de noms est suffisant. –

18

Je crois que cela devrait fonctionner:

myObject = (MyAbstractClass)Activator.CreateInstance(null, childClassString); 

Le null dans les premiers paramètre par défaut de l'ensemble exécution en cours. Pour plus Référence: MSDN

edit: oublié de jeter à MyAbstractClass

1

J'ai eu quelques difficultés à mettre quelques-unes des réponses ici parce que je cherchais à instancier un objet à partir d'un ensemble différent (mais dans la même solution). J'ai donc pensé poster ce que j'ai trouvé au travail.

Premièrement, la méthode Activator.CreateInstance a plusieurs surcharges. Si vous appelez simplement Activator.CreateInstance(Type.GetType("MyObj")), cela suppose que l'objet est défini dans l'assembly en cours et il renvoie un MyObj.

Si vous l'appelez comme recommandé dans les réponses ici: Activator.CreateInstance(string AssemblyName, string FullyQualifiedObjectName), alors il renvoie à la place un ObjectHandle, et vous devez appeler Unwrap() dessus pour obtenir votre objet. Cette surcharge est utile lorsque vous essayez d'appeler une méthode définie dans un assembly différent (BTW, vous pouvez utiliser cette surcharge dans l'assembly en cours, laissez simplement le paramètre AssemblyName null).

Maintenant, j'ai trouvé que la suggestion ci-dessus pour utiliser typeof(ParentNamespace.ChildNamespace.MyObject).AssemblyQualifiedName pour AssemblyName m'a effectivement donné des erreurs, et je ne pouvais pas obtenir que cela fonctionne. J'obtiendrais System.IO.FileLoadException (impossible de charger le fichier ou l'assemblage ...).

Ce que je ne se rendre au travail est la suivante:

var container = Activator.CreateInstance(@"AssemblyName",@"ParentNamespace.ChildNamespace.MyObject"); 
MyObject obj = (MyObject)container.Unwrap(); 
obj.DoStuff(); 
Questions connexes