Créer une instance d'une classe à partir d'une chaîne

218

Existe-t-il un moyen de créer une instance d'une classe basée sur le fait que je connais le nom de la classe lors de l'exécution. En gros, j'aurais le nom de la classe dans une chaîne.

PeteT
la source
Vous semblez avoir décrit la solution que vous souhaitez mettre en œuvre, mais pas le problème que vous essayez de résoudre. Peut-être que vous essayez de faire quelque chose avec l'extensibilité, auquel cas je vous suggère de consulter le cadre d'extensibilité gérée .
Jay Bazuzi

Réponses:

159

Jetez un œil à la méthode Activator.CreateInstance .

Matt Hamilton
la source
15
Associé à de bons exemples: stackoverflow.com/questions/493490/…
John S.
Cet article sera également pertinent, car votre type doit être trouvé: stackoverflow.com/questions/1825147/…
Brad Parks
1
Exemples: stackoverflow.com/questions/7598088/…
profimedica
4
Par exemple:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
Endy Tjahjono
2
Remarque importante ici: .Unwrap () pour dépasser la poignée d'accès distant afin que vous puissiez réellement effectuer les transtypages. @Endy - Merci
Roger Willcocks
77

C'est assez simple. Supposons que votre nom de classe est Caret que l'espace de noms est Vehicles, puis passez le paramètre en tant que Vehicles.Carqui renvoie l'objet de type Car. Comme cela, vous pouvez créer n'importe quelle instance de n'importe quelle classe de manière dynamique.

public object GetInstance(string strFullyQualifiedName)
{         
     Type t = Type.GetType(strFullyQualifiedName); 
     return  Activator.CreateInstance(t);         
}

Si votre nom complet (c'est- Vehicles.Carà- dire dans ce cas) se trouve dans un autre assembly, le Type.GetTypesera nul. Dans de tels cas, vous devez parcourir tous les assemblys et trouver le fichier Type. Pour cela, vous pouvez utiliser le code ci-dessous

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

Maintenant, si vous voulez appeler un constructeur paramétré, procédez comme suit

Activator.CreateInstance(t,17); // Incase you are calling a constructor of int type

au lieu de

Activator.CreateInstance(t);
Sarath Avanavu
la source
Comment l'utiliser sans cast et comment faire le cast à partir de la chaîne donnée ??
TaW
1
@TaW - pour utiliser une instance de classe, vous aurez besoin d'avoir une certaine connaissance de ce qu'elle va faire - sinon vous ne pourrez pas l'utiliser. Le cas d'utilisation le plus courant serait de lancer une interface qui vous donnerait un contrat prédéfini. (Cela est valable sauf si vous utilisez du dynamiccode - voir stackoverflow.com/a/2690661/904521 )
Tomer Cagan
1
Ne pas encoder le type de la variable dans son nom. Par exemple: il n'est pas nécessaire de préfixer strFullyQualifiedNameavec str, fullyQualifiedNamefera le travail.
Mehdi Dehghani
Le mot str- clé est utilisé dans le cadre de la convention de dénomination des variables. Certaines organisations et certains projets insistent pour suivre cela, c'est pourquoi j'ai utilisé. Si vous auriez travaillé dans certaines oraganisations / projets, vous le saurez. Comme vous l'avez dit sans, strcela fera également l'affaire :) @MehdiDehghani
Sarath Avanavu
1
Je sais, il n'est pas nécessaire de travailler dans une organisation pour connaître les conventions de dénomination, cette convention connue sous le nom de notation hongroise et c'est l'une des conventions de dénomination mauvaises et obsolètes . spécialement pour C #
Mehdi Dehghani
55

J'ai utilisé cette méthode avec succès:

System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string className)

Vous devrez convertir l'objet renvoyé en votre type d'objet souhaité.

Ray Li
la source
9
J'essaie d'imaginer un scénario dans lequel la création de l'objet via le nom de classe, puis la conversion en ce type aurait un sens.
MusiGenesis
13
Je vois ce que tu veux dire. Cela semble redondant. Si vous connaissez le nom de la classe, pourquoi avez-vous besoin de la chaîne dynamique? Une situation pourrait être que votre transtypage en classe de base et la chaîne représentent les descendants de cette classe de base.
Ray Li
4
Si la classe de base est connue, vous pouvez utiliser la classe de base ou une interface de celle-ci comme argument pour passer des descendants sans réflexion.
Garet Claborn
3
Scénario utile: vous n'avez besoin que des interfaces de sérialisation ou de toute autre interface assez courante. Vous ne le lancerez pas à la classe, mais au moins à quelque chose de plus qu'un objet
Harald Coppoolse
2
Comment faire le cast à partir de la chaîne donnée ??
TaW
23

Ma question aurait probablement dû être plus précise. Je connais en fait une classe de base pour la chaîne, donc je l'ai résolue par:

ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

La classe Activator.CreateInstance a différentes méthodes pour réaliser la même chose de différentes manières. J'aurais pu le lancer sur un objet mais ce qui précède est le plus utile à ma situation.

PeteT
la source
4
Au lieu de répondre dans la section des questions, je vous suggère de modifier votre question et de noter les modifications. Vous obtiendrez des réponses plus / meilleures pour le faire.
Jason Jackson
Merci d'avoir publié la ligne de code spécifique qui a fonctionné pour vous. Trier toutes les surcharges CreateInstance et les différentes façons de générer des types me prenait beaucoup de temps, ce que vous m'avez sauvé.
Ethel Evans
4

Je sais que je suis en retard dans le jeu ... mais la solution que vous recherchez pourrait être la combinaison de ce qui précède et l'utilisation d'une interface pour définir vos aspects accessibles au public.

Ensuite, si toutes vos classes qui seraient générées de cette façon implémentent cette interface, vous pouvez simplement transtyper en tant que type d'interface et travailler avec l'objet résultant.

Denny
la source
4

Pour créer une instance d'une classe à partir d'un autre projet dans la solution, vous pouvez obtenir l'assembly indiqué par le nom de n'importe quelle classe (par exemple BaseEntity) et créer une nouvelle instance:

  var newClass = System.Reflection.Assembly.GetAssembly(typeof(BaseEntity)).CreateInstance("MyProject.Entities.User");
asd
la source
3

Par exemple, si vous stockez des valeurs de différents types dans un champ de base de données (stocké sous forme de chaîne) et que vous avez un autre champ avec le nom du type (c'est-à-dire String, bool, int, MyClass), alors à partir de ces données de champ, vous pourriez, en théorie, créez une classe de tout type à l'aide du code ci-dessus et remplissez-la avec la valeur du premier champ. Cela dépend bien sûr du type que vous stockez ayant une méthode pour analyser les chaînes dans le type correct. J'ai utilisé cela plusieurs fois pour stocker les paramètres de préférence utilisateur dans une base de données.

Greg Osborne
la source
-11
ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

pourquoi voulez-vous écrire un code comme celui-ci? Si une classe «ReportClass» est disponible, vous pouvez l'instancier directement comme indiqué ci-dessous.

ReportClass report = new ReportClass();

Le code ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));est utilisé lorsque vous n'avez pas la classe nécessaire disponible, mais que vous souhaitez instancier et / ou invoquer une méthode dynamiquement.

Je veux dire qu'il est utile lorsque vous connaissez l'assembly mais en écrivant le code, vous n'avez pas la classe ReportClassdisponible.

Asish
la source