2010-08-07 56 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)) 
相关问题