Erstellen Sie eine Instanz einer Klasse aus einer Zeichenfolge

217

Gibt es eine Möglichkeit, eine Instanz einer Klasse basierend auf der Tatsache zu erstellen, dass ich den Namen der Klasse zur Laufzeit kenne. Grundsätzlich hätte ich den Namen der Klasse in einer Zeichenfolge.

PeteT
quelle
Sie scheinen die Lösung beschrieben zu haben, die Sie implementieren möchten, aber nicht das Problem, das Sie lösen möchten. Vielleicht versuchen Sie etwas mit Erweiterbarkeit zu tun. In diesem Fall schlage ich vor, dass Sie sich das Managed Extensibility Framework ansehen .
Jay Bazuzi

Antworten:

159

Schauen Sie sich die Activator.CreateInstance- Methode an.

Matt Hamilton
quelle
15
Verwandt mit tollen Beispielen: stackoverflow.com/questions/493490/…
John S.
Auch dieser Beitrag wird relevant sein, da Ihr Typ gefunden werden muss: stackoverflow.com/questions/1825147/…
Brad Parks
1
Beispiele: stackoverflow.com/questions/7598088/…
profimedica
4
Zum Beispiel:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
Endy Tjahjono
2
Wichtiger Hinweis hier: .Unwrap (), um das Remoting-Handle zu überwinden, damit Sie die Casts tatsächlich ausführen können. @ Endy - Danke
Roger Willcocks
77

Es ist ziemlich einfach. Angenommen, Ihr Klassenname ist Carund der Namespace ist Vehicles, und übergeben Sie den Parameter, Vehicles.Carder ein Objekt vom Typ zurückgibt Car. Auf diese Weise können Sie jede Instanz einer beliebigen Klasse dynamisch erstellen.

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

Wenn sich Ihr vollständig qualifizierter Name (dh Vehicles.Carin diesem Fall) in einer anderen Assembly befindet, ist der NameType.GetType null. In solchen Fällen haben Sie eine Schleife durch alle Baugruppen und finden die Type. Dafür können Sie den folgenden Code verwenden

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

Wenn Sie nun einen parametrisierten Konstruktor aufrufen möchten, gehen Sie wie folgt vor

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

anstatt

Activator.CreateInstance(t);
Sarath Avanavu
quelle
Wie benutzt man es ohne Casting und wie macht man das Casting aus der angegebenen Saite ?
TaW
1
@TaW - Um eine Klasseninstanz verwenden zu können, müssen Sie einige Kenntnisse darüber haben, was sie tun wird. Andernfalls können Sie sie nicht verwenden. Der häufigste Anwendungsfall hierfür ist das Casting auf eine Schnittstelle, die Ihnen einen vordefinierten Vertrag gibt. (Dies gilt, sofern Sie keinendynamic Code verwenden - siehe stackoverflow.com/a/2690661/904521 )
Tomer Cagan
1
Darin Namen nicht den Typ der Variablen kodieren, zum Beispiel:. Es besteht keine Notwendigkeit, Präfix strFullyQualifiedNamemit str, fullyQualifiedNamewird die Arbeit machen.
Mehdi Dehghani
Das Schlüsselwort strwird als Teil der Namenskonvention für Variablen verwendet. Bestimmte Organisationen und Projekte bestehen darauf, dies zu befolgen, daher habe ich verwendet. Wenn Sie in bestimmten Organisationen / Projekten gearbeitet hätten, wissen Sie dies. Wie Sie sagten, auch ohne strwird es den Job machen :) @MehdiDehghani
Sarath Avanavu
1
Ich weiß, es ist nicht nötig, in einer Organisation zu arbeiten, um über Namenskonventionen Bescheid zu wissen. Diese Konvention ist als ungarische Notation bekannt und eine der schlechten und veralteten Namenskonventionen da draußen. speziell für C #
Mehdi Dehghani
55

Ich habe diese Methode erfolgreich angewendet:

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

Sie müssen das zurückgegebene Objekt in den gewünschten Objekttyp umwandeln.

Ray Li
quelle
9
Ich versuche mir ein Szenario vorzustellen, in dem das Erstellen des Objekts über den Klassennamen und das anschließende Umwandeln als dieser Typ überhaupt Sinn macht.
MusiGenesis
13
Ich verstehe was du meinst. Es scheint überflüssig. Wenn Sie den Klassennamen kennen, warum benötigen Sie die dynamische Zeichenfolge? Eine Situation könnte sein, dass Ihr Casting in eine Basisklasse und die Zeichenfolge Nachkommen dieser Basisklasse darstellen.
Ray Li
4
Wenn die Basisklasse bekannt ist, können Sie die Basisklasse oder eine Schnittstelle davon als Argument verwenden, um Nachkommen ohne Reflexion zu übergeben.
Garet Claborn
3
Nützliches Szenario: Sie benötigen nur die Serialisierungsschnittstellen oder eine andere häufig verwendete Schnittstelle. Sie werden es nicht in die Klasse werfen, sondern zumindest in etwas mehr als ein Objekt
Harald Coppoolse
2
Wie mache ich die Besetzung aus der angegebenen Saite ?
TaW
23

Wahrscheinlich hätte meine Frage spezifischer sein sollen. Ich kenne tatsächlich eine Basisklasse für den String, also löste ich sie durch:

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

Die Activator.CreateInstance-Klasse verfügt über verschiedene Methoden, um dasselbe auf unterschiedliche Weise zu erreichen. Ich hätte es auf ein Objekt werfen können, aber das Obige ist für meine Situation am nützlichsten.

PeteT
quelle
4
Anstatt im Fragenbereich zu antworten, würde ich vorschlagen, dass Sie Ihre Frage bearbeiten und die Änderungen notieren. Sie erhalten mehr / bessere Antworten dafür.
Jason Jackson
Vielen Dank, dass Sie die Codezeile veröffentlicht haben, die für Sie funktioniert hat. Das Durchsuchen aller CreateInstance-Überladungen und der verschiedenen Methoden zum Generieren von Typen hat mich viel Zeit gekostet, was Sie mir erspart haben.
Ethel Evans
4

Ich weiß, dass ich zu spät zum Spiel komme ... aber die Lösung, nach der Sie suchen, könnte die Kombination der oben genannten sein und die Verwendung einer Schnittstelle zum Definieren öffentlich zugänglicher Aspekte Ihrer Objekte.

Wenn dann alle Ihre Klassen, die auf diese Weise generiert würden, diese Schnittstelle implementieren, können Sie sie einfach als Schnittstellentyp umwandeln und mit dem resultierenden Objekt arbeiten.

Denny
quelle
4

Um eine Instanz einer Klasse aus einem anderen Projekt in der Lösung zu erstellen, können Sie die Assembly mit dem Namen einer beliebigen Klasse (z. B. BaseEntity) anzeigen lassen und eine neue Instanz erstellen:

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

Wenn Sie beispielsweise Werte verschiedener Typen in einem Datenbankfeld (als Zeichenfolge gespeichert) speichern und ein anderes Feld mit dem Typnamen (dh Zeichenfolge, bool, int, MyClass) haben, können Sie aus diesen Felddaten möglicherweise Erstellen Sie mit dem obigen Code eine Klasse eines beliebigen Typs und füllen Sie sie mit dem Wert aus dem ersten Feld. Dies hängt natürlich vom Typ ab, den Sie speichern, und verfügt über eine Methode zum Parsen von Zeichenfolgen in den richtigen Typ. Ich habe dies oft verwendet, um Benutzereinstellungen in einer Datenbank zu speichern.

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

Warum willst du so einen Code schreiben? Wenn eine Klasse 'ReportClass' verfügbar ist, können Sie diese wie unten gezeigt direkt instanziieren.

ReportClass report = new ReportClass();

Der Code ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));wird verwendet, wenn Sie nicht über die erforderliche Klasse verfügen, aber eine Methode dynamisch instanziieren und / oder aufrufen möchten.

Ich meine, es ist nützlich, wenn Sie die Assembly kennen, aber während Sie den Code schreiben, steht Ihnen die Klasse nicht zur ReportClassVerfügung.

Asish
quelle