2010-08-07 64 views
5

是否有一種方法可以使用字符串作爲類名來動態創建對象?Visual Basic:使用字符串作爲名稱動態創建對象

我已經離開VB好幾年了,但爲了解決另一種語言的問題,我不得不在這個開發包裝。我有一個工廠方法來動態創建並返回基於來自其他地方的輸入類型的對象。提供的輸入是要從中創建對象的類名。正常的語法意味着整個類必須明確拼寫出來。要做到這一點這種方式,可以從字面上有數百個,如果/然後是或案件處理中引用庫中的所有可用類/對象的選擇:

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

我希望,而不是減少所有這種情況下處理,以單行:IE瀏覽器...

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

在PHP中,這是像這樣處理......

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

編輯:縱觀一些問題的答案,我覺得我在這裏過着我的頭。我還是設法得到它的工作使用Assembly類的this CreateInstance方法的變化,即使我更感興趣的是this variation giving more options,包括提供構造參數...

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) 

換句話說,它需要一個方法來做這個,而不是任何固有的語言語法? This Activator variation在使用完整的組合字符串和類路徑時也可以工作。我很可疑CreateInstance可能沒有完全的能力讓我把對象當作正常調用,例如obj = new System.Windows.Forms.Button。這就是爲什麼我不能簡單地使用CreateObject。如果沒有自然語言特徵允許您用類名替換字符串,那麼是否有人能夠洞察使用CreateInstance可以預期哪些限制?

另外,是否有基本的Activator.CreateInstance(Unwrap之後)和Assembly.CreateInstance方法之間的區別?

回答

10

這可能會做你想要什麼/測試的工作;在頂部切換類型註釋以查看。

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

不錯。 Form1_Load()'實際上將通過COM通過另一種語言處理。行o = Assembly.Load(ay).CreateInstance(fullyQualifiedClassName)'應該這樣做。 – 2010-08-09 04:27:53

0

查看Activator.CreateInstance(Type)方法。

如果輸入的是你應該能夠一類的名稱做到這一點:

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

你必須用的GetType調用撥弄,以確保您給它足夠的信息,但在大多數情況下只該班的名字應該工作。

+0

相信的GetType()需要一個類型,因此將拋出一個錯誤。 Type.Gettype(「System.Windows.Forms.Button」)返回null。 – 2010-08-07 23:31:51

+0

我的vb有點生疏,但這絕對應該工作。不知道爲什麼你得到null,但這裏沒有傳遞字符串的GetType文檔:http://msdn.microsoft.com/en-us/library/w3f99sx1.aspx – jwsample 2010-08-07 23:49:11

+0

這個例子幾乎是我最初的東西使用,除了用類型的蓋特派方法代替。我相信這讓我不知道如何先找到System.Windows.Forms.Button類型。 – 2010-08-08 00:11:57

3

我很確定Activator用於遠程處理。你想要做的是使用反射來獲得constor並在這裏調用它是一個例子 http://www.eggheadcafe.com/articles/20050717.asp

編輯:我誤導了Activator,直到jwsample糾正我。

我認爲你的問題在於你的程序集是GetType用來試圖找到Button的程序集。您需要從正確的裝配中調用它。

這應該這樣做

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

哇,你用這個編輯改變了你的文章的全部內容,現在我以前的評論看起來像瘋子的瘋話。 – jwsample 2010-08-07 23:52:16

+0

對不起。我把它放回去了。 – 2010-08-08 07:07:23

+1

良好的線索。恨挑剔,但與Activator.CreateInstance,因爲它返回一個句柄,它需要你調用它的句柄Unwrap方法來完成創建對象。另外,根據http://msdn.microsoft.com/en-us/library/system.reflection.assembly.loadwithpartialname.aspx,Assembly.LoadWithPartialName方法已過時。恥辱,因爲我真的可以使用它,而不是嘗試尋找版本,文化和密鑰。 – 2010-08-09 04:12:41

0

這是一個非常簡單的方法,同時通過互聯網翻箱倒櫃,我發現:

dynamicControl = Activator.CreateInstance(Type.GetType("MYASSEMBLYNAME." + controlNameString)) 
相關問題