2010-08-07 11 views
5

Gibt es eine Möglichkeit, ein Objekt dynamisch zu erstellen, indem Sie eine Zeichenfolge als Klassennamen verwenden?Visual Basic: Objekte dynamisch mithilfe einer Zeichenfolge als Name erstellen

Ich bin seit einigen Jahren aus VB, aber um ein Problem in einer anderen Sprache zu lösen, bin ich gezwungen, einen Wrapper in diesem zu entwickeln. Ich habe eine Factory-Methode zum dynamischen Erstellen und Zurückgeben eines Objekts eines Typs basierend auf Eingaben von woanders. Die angegebene Eingabe ist der Klassenname, aus dem ein Objekt erstellt werden soll. Normale Syntax bedeutet, dass die gesamte Klasse explizit buchstabiert werden muss. Um es auf diese Art und Weise zu tun, könnte es buchstäblich Hunderte von if/then ist oder Fälle zu behandeln alle verfügbaren Klasse/Objekt Auswahl innerhalb der referenzierten Libs:

If c_name = "Button" then obj = new System.Windows.Forms.Button 
If c_name = "Form" then obj = new System.Windows.Forms.Form 
.... 

Ich hoffe, anstatt all diesen Fall zu reduzieren Transporters eine einzige Zeile: IE ...

my_class_name = "whateverclass" 
obj = new System.Windows.Forms.my_class_name() 

In PHP wird dies wie so behandelt ...

$my_class_name = "whateverclass"; 
$obj = new $my_class_name(); 

Edit: auf einige der Antworten der Suche Ich denke, ich bin hier über meinen Kopf hinweg. Ich habe es geschafft, um es mit this CreateInstance Methode Variation der Assembly-Klasse arbeiten, obwohl ich in this variation giving more options mehr daran interessiert bin, einschließlich Parameter liefert konstruieren ...

my_type_name = "System.Windows.Forms.Button" 
asmb_name = "System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
button1 = Reflection.Assembly.Load(asmb_name).CreateInstance(my_type_name) 

Mit anderen Worten, es braucht eine Methode zu tun Dies und keine inhärente Sprachsyntax? This Activator variation funktionierte auch, wenn der vollständige Assembly-String und Klassenpfad verwendet wird. Ich bin misstrauisch CreateInstance hat möglicherweise nicht die volle Fähigkeit, Objekte so zu behandeln, als wären sie normal aufgerufen worden, zB obj = new System.Windows.Forms.Button. Deshalb kann ich nicht einfach CreateObject verwenden. Wenn es keine natürliche Sprachfunktion gibt, mit der Sie einen Klassennamen für eine Zeichenfolge ersetzen können, hat irgendjemand einen Einblick, welche Art von Einschränkungen ich von der Verwendung von CreateInstance erwarten kann?

Gibt es auch einen Unterschied zwischen grundlegenden Activator.CreateInstance (nach dem Unwrap) und Assembly.CreateInstance Methoden?

Antwort

10

Dies wird wahrscheinlich tun, was Sie wollen/Arbeits getestet wurden; Wechseln Sie den Typ Kommentar oben um zu sehen.

Imports System.Reflection 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
    '   Dim fullyQualifiedClassName as String = "System.Windows.Forms.TextBox" 
    Dim fullyQualifiedClassName As String = "System.Windows.Forms.Button" 
    Dim o = fetchInstance(fullyQualifiedClassName) 
    ' sometime later where you can narrow down the type or interface... 
    Dim b = CType(o, Control) 
    b.Text = "test" 
    b.Top = 10 
    b.Left = 10 
    Controls.Add(b) 
End Sub 

Private Function fetchInstance(ByVal fullyQualifiedClassName As String) As Object 
    Dim nspc As String = fullyQualifiedClassName.Substring(0, fullyQualifiedClassName.LastIndexOf("."c)) 
    Dim o As Object = Nothing 
    Try 
     For Each ay In Assembly.GetExecutingAssembly().GetReferencedAssemblies() 
      If (ay.Name = nspc) Then 
       o = Assembly.Load(ay).CreateInstance(fullyQualifiedClassName) 
       Exit For 
      End If 
     Next 
    Catch 
    End Try 
    Return o 
End Function 
+1

Schön. 'Form1_Load()' wird tatsächlich über eine andere Sprache für mich über COM abgewickelt. Die Zeile 'o = Assembly.Load (ay) .CreateInstance (fullyQualifiedClassName)' sollte es tun. –

0

Werfen Sie einen Blick auf die Activator.CreateInstance (Type) -Methode.

Wenn Sie Ihre Eingabe der Name einer Klasse sollten Sie in der Lage sein, dies zu tun:

Dim obj As Object = Activator.CreateInstance(GetType("Name_Of_Your_Class")) 

Sie werden mit dem GetType Aufruf zur Geige müssen sicherstellen, dass Sie es genug Informationen geben, aber für die meisten Fälle nur Der Name der Klasse sollte funktionieren.

+0

Ich glaube Gettype() eine Art erwartet, so wird ein Fehler ausgegeben. Type.Gettype ("System.Windows.Forms.Button") gibt null zurück. –

+0

Mein Vb ist ein bisschen eingerostet, aber das sollte definitiv funktionieren. Nicht sicher, warum Sie null erhalten, aber hier ist die GetType-Dokumentation für die Übergabe einer Zeichenfolge in: http://msdn.microsoft.com/en-us/library/w3f99sx1.aspx – jwsample

+0

Das Beispiel ist ziemlich genau das, was ich ursprünglich war Verwenden, außer mit der Gettype-Methode von Type stattdessen. Ich glaube, das lässt mich stecken bleiben und einen Weg finden, den System.Windows.FormsButton-Typ zuerst zu finden. –

3

Ich bin ziemlich sicher Activator wird für das Remoting verwendet. Was Sie tun möchten, ist Reflektion zu verwenden, um den Constor zu erhalten und es hier ist ein Beispiel http://www.eggheadcafe.com/articles/20050717.asp

EDIT: Ich war über Activator fehlgeleitet, bis jwsample mich korrigiert.

Ich denke, das Problem, das Sie haben, ist, dass Ihre Assembly diejenige ist, die GetType verwendet, um Button zu finden und zu finden. Sie müssen es von der richtigen Baugruppe aufrufen.

Dies sollte es tun

Dim asm As System.Reflection.Assembly = System.Reflection.Assembly.LoadWithPartialName("System.Windows.Forms") 


Dim obj As Object = Activator.CreateInstance(asm.GetType("System.Windows.Forms.Button")) 
+1

Wow, Sie haben den gesamten Inhalt Ihres Posts mit dieser Änderung geändert und nun sieht mein vorheriger Kommentar wie die Raserei eines Verrückten aus. – jwsample

+0

Entschuldigung. Ich lege es zurück. –

+1

Gute führt. Hass auf Nitpick, aber mit Activator.CreateInstance, weil es ein Handle zurückgibt, erfordert es, dass Sie die Handle Unwrap-Methode darauf aufrufen, um die Erstellung des Objekts abzuschließen. Außerdem ist die Assembly.LoadWithPartialName-Methode gemäß http://msdn.microsoft.com/en-us/library/system.reflection.assembly.loadwithpartialname.aspx veraltet. Schade, weil ich es wirklich nutzen könnte, anstatt herumzualbern und nach Versionen, Kulturen und Schlüsseln zu suchen. –

0

Hier ist eine wirklich einfache Möglichkeit, die ich gefunden habe, während sie durch das Internet wühlen:

dynamicControl = Activator.CreateInstance(Type.GetType("MYASSEMBLYNAME." + controlNameString))