2010-08-07 15 views
5

C'è un modo per creare dinamicamente un oggetto usando una stringa come nome della classe?Visual Basic: crea dinamicamente oggetti usando una stringa come nome

Sono fuori VB da diversi anni, ma per risolvere un problema in un'altra lingua, sono costretto a sviluppare un wrapper in questo. Ho un metodo factory per creare e restituire dinamicamente un oggetto di un tipo basato sull'input da altrove. L'input fornito è pensato per essere il nome della classe da cui creare un oggetto. La sintassi normale significa che l'intera classe deve essere esplicitamente enunciata. Per farlo in questo modo, ci potrebbe essere letteralmente centinaia di if/then è o casi per gestire tutte le scelte della classe/oggetto disponibili all'interno delle librerie di riferimento:

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

spero invece di ridurre tutta questa gestione a caso una sola riga: IE ...

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

In PHP, questo viene gestito in questo modo ...

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

Edit: Guardando alcune delle risposte , Penso di essere sopra la mia testa qui. Sono riuscito a farlo funzionare con this CreateInstance metodo di variazione della classe dell'Assemblea, anche se io sono più interessato a this variation giving more options, tra cui la fornitura di costruire parametri ...

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) 

In altre parole, ci vuole un metodo per fare questo, e nessuna sintassi del linguaggio inerente? This Activator variation ha funzionato anche quando viene utilizzata la stringa di assemblaggio completa e il percorso di classe. Sono sospettoso che CreateInstance potrebbe non avere la piena capacità di lasciarmi trattare gli oggetti come se fossero chiamati normalmente, ovvero obj = new System.Windows.Forms.Button. Questo è il motivo per cui non posso usare semplicemente CreateObject. Se non esiste una funzione di linguaggio naturale che ti permetta di sostituire un nome di classe per una stringa, qualcuno ha qualche idea in che tipo di limitazioni posso aspettarmi dall'uso di CreateInstance?

Inoltre, c'è anche una differenza tra i metodi di base Activator.CreateInstance (dopo Unwrap) e Assembly.CreateInstance?

risposta

10

Questo probabilmente fare quello che vuoi/Funzionamento provato; cambia il commento del tipo in alto per vedere.

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

Bello. 'Form1_Load()' sarà effettivamente gestito tramite un'altra lingua per me tramite COM. La riga 'o = Assembly.Load (ay) .CreateInstance (fullyQualifiedClassName)' dovrebbe farlo. –

0

Dai un'occhiata al metodo Activator.CreateInstance (Type).

Se il vostro input è il nome di una classe che si dovrebbe essere in grado fare questo:

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

Dovrete giocherellare con la chiamata GetType per assicurarsi si dà abbastanza informazioni, ma per la maggior parte dei casi solo il nome della classe dovrebbe funzionare.

+0

credo Gettype() si aspetta un tipo, quindi viene generato un errore. Type.Gettype ("System.Windows.Forms.Button") restituisce null. –

+0

Il mio VB è un po 'arrugginito ma dovrebbe funzionare sicuramente. Non sei sicuro del motivo per cui stai ricevendo il valore null, ma qui non c'è la documentazione GetType per il passaggio di una stringa in: http://msdn.microsoft.com/en-us/library/w3f99sx1.aspx – jwsample

+0

L'esempio è praticamente ciò che ero originariamente usando, tranne con il metodo Gettype di Type. Credo che questo mi permetta di trovare un modo per dare la caccia al tipo System.Windows.Forms.Button. –

3

Sono abbastanza sicuro che Activator sia utilizzato per servizi remoti. Quello che vuoi fare è usare il reflection per ottenere il constor e invocarlo ecco un esempio http://www.eggheadcafe.com/articles/20050717.asp

EDIT: Sono stato sviato su Activator fino a che jwsample non mi ha corretto.

Penso che il problema è che il vostro assembly è quello che GetType sta usando per cercare e trovare Button. Devi chiamarlo dall'assemblea giusta.

Questo dovrebbe farlo

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, hai modificato l'intero contenuto del tuo post con quella modifica e ora il mio commento precedente assomiglia ai deliri di un pazzo. – jwsample

+0

Mi dispiace per quello. L'ho rimesso. –

+1

Buoni contatti. Odio il nitpick, ma con Activator.CreateInstance, poiché restituisce un handle, richiede che chiami il metodo Unwrap dell'handle per completare la creazione dell'oggetto. Inoltre, il metodo Assembly.LoadWithPartialName è obsoleto in base a http://msdn.microsoft.com/en-us/library/system.reflection.assembly.loadwithpartialname.aspx. Peccato, perché potrei davvero usarlo invece di cercare di trovare versioni, culture e chiavi. –

0

Ecco un modo davvero semplice che ho trovato frugando attraverso internet:

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