Crea un'istanza di una classe da una stringa


218

Esiste un modo per creare un'istanza di una classe in base al fatto che conosco il nome della classe in fase di esecuzione. Fondamentalmente avrei il nome della classe in una stringa.


Sembra che tu abbia descritto la soluzione che desideri implementare, ma non il problema che stai cercando di risolvere. Forse stai provando a fare qualcosa con estensibilità, nel qual caso ti suggerisco di dare un'occhiata al Managed Extensibility Framework .
Jay Bazuzi,

Risposte:


159

Dai un'occhiata al metodo Activator.CreateInstance .


15
Correlati a grandi esempi: stackoverflow.com/questions/493490/…
John S.

Anche questo post sarà pertinente, poiché il tuo tipo deve essere trovato: stackoverflow.com/questions/1825147/…
Brad Parks


4
Ad esempio:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
Endy Tjahjono,

2
Nota importante qui:. Unwrap () per superare l'handle di remoting in modo da poter effettivamente eseguire i cast. @Endy - Grazie
Roger Willcocks,

77

È piuttosto semplice. Supponiamo che il tuo nome classe sia Care lo spazio dei nomi sia Vehicles, quindi passa il parametro come Vehicles.Carche restituisce l'oggetto di tipo Car. In questo modo puoi creare dinamicamente qualsiasi istanza di qualsiasi classe.

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

Se il tuo nome completo (ovvero, Vehicles.Carin questo caso) si trova in un altro assembly, Type.GetTypesarà nullo. In tali casi, è necessario scorrere tutti gli assiemi e trovare il file Type. Per questo puoi usare il codice qui sotto

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

Ora, se vuoi chiamare un costruttore con parametri, procedi come segue

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

invece di

Activator.CreateInstance(t);

Come usarlo senza casting e come eseguire il cast dalla stringa specificata ??
TaW

1
@TaW - per usare un'istanza di classe dovrai avere una certa conoscenza di ciò che sta per fare, altrimenti non sarai in grado di usarlo. Il caso d'uso più comune per questo sarebbe il casting su qualche interfaccia che ti dia un contratto predefinito. (Questo vale a meno che tu non stia usando il dynamiccodice - vedi stackoverflow.com/a/2690661/904521 )
Tomer Cagan

1
Non codificare il tipo della variabile nel suo nome, per esempio:. Non v'è alcuna necessità di prefisso strFullyQualifiedNamecon str, fullyQualifiedNamefarà il lavoro.
Mehdi Dehghani,

La parola chiave strviene utilizzata come parte della convenzione di denominazione per le variabili. Alcune organizzazioni e progetti insistono nel seguire questo, quindi ho usato. Se avessi lavorato in determinati oraganizzazioni / progetti, lo saprai. Come hai detto senza str, farà anche il lavoro :) @MehdiDehghani
Sarath Avanavu

1
So che non c'è bisogno di lavorare in nessuna organizzazione per conoscere le convenzioni di denominazione, questa convenzione nota come notazione ungherese ed è una delle convenzioni di denominazione cattive e deprecate là fuori. appositamente per C #
Mehdi Dehghani,

55

Ho usato questo metodo con successo:

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

Dovrai trasmettere l'oggetto restituito al tipo di oggetto desiderato.


9
Sto cercando di immaginare uno scenario in cui creare l'oggetto tramite il nome della classe e poi lanciarlo come quel tipo avrebbe alcun senso.
MusiGenesis,

13
Capisco cosa vuoi dire. Sembra ridondante. Se conosci il nome della classe, perché hai bisogno della stringa dinamica? Una situazione potrebbe essere che il casting in una classe base e la stringa rappresenti i discendenti di quella classe base.
Ray Li,

4
Se la classe base è nota, è possibile utilizzare la classe base o un'interfaccia come argomento per passare discendenti senza riflessione.
Garet Claborn,

3
Scenario utile: sono necessarie solo le interfacce di serializzazione o qualsiasi altra interfaccia abbastanza comune. Non lo
lancerai

2
Come eseguire il cast dalla stringa specificata ??
TaW

23

Probabilmente la mia domanda avrebbe dovuto essere più specifica. In realtà conosco una classe base per la stringa così risolta da:

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

La classe Activator.CreateInstance ha vari metodi per ottenere la stessa cosa in modi diversi. Avrei potuto lanciarlo su un oggetto ma quanto sopra è di grande utilità per la mia situazione.


4
Invece di rispondere nella sezione delle domande, ti suggerisco di modificare la tua domanda e prendere nota delle modifiche. Otterrai risposte più / migliori per farlo.
Jason Jackson,

Grazie per aver pubblicato la riga di codice specifica che ha funzionato per te. L'ordinamento di tutti i sovraccarichi di CreateInstance e dei diversi modi di generare Tipi mi ha richiesto molto tempo, cosa che mi hai salvato.
Ethel Evans,

4

So di essere in ritardo al gioco ... ma la soluzione che stai cercando potrebbe essere la combinazione di quanto sopra e l'utilizzo di un'interfaccia per definire gli aspetti accessibili al pubblico dei tuoi oggetti.

Quindi, se tutte le classi che verrebbero generate in questo modo implementano tale interfaccia, puoi semplicemente eseguire il cast come tipo di interfaccia e lavorare con l'oggetto risultante.


4

Per creare un'istanza di una classe da un altro progetto nella soluzione, è possibile ottenere l'assemblaggio indicato dal nome di qualsiasi classe (ad esempio BaseEntity) e creare una nuova istanza:

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

3

Ad esempio, se si memorizzano valori di vari tipi in un campo del database (memorizzato come stringa) e si dispone di un altro campo con il nome del tipo (ovvero String, bool, int, MyClass), quindi dai dati di quel campo, è possibile, presumibilmente, crea una classe di qualsiasi tipo usando il codice sopra e popolala con il valore dal primo campo. Questo ovviamente dipende dal tipo che stai memorizzando con un metodo per analizzare le stringhe nel tipo corretto. L'ho usato molte volte per memorizzare le impostazioni delle preferenze dell'utente in un database.


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

perché vuoi scrivere un codice come questo? Se è disponibile una classe "ReportClass", è possibile creare un'istanza direttamente come mostrato di seguito.

ReportClass report = new ReportClass();

Il codice ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass)); viene utilizzato quando non si dispone della classe necessaria disponibile, ma si desidera creare un'istanza e / o invocare un metodo in modo dinamico.

Voglio dire, è utile quando conosci l'assembly ma mentre scrivi il codice non hai la classe ReportClassdisponibile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.