vb.net Visual Basic:使用字符串作为名称动态创建对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3432317/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 14:59:42  来源:igfitidea点击:

Visual Basic: dynamically create objects using a string as the name

vb.netobject

提问by bob-the-destroyer

Is there a way to dynamically create an object using a string as the class name?

有没有办法使用字符串作为类名动态创建对象?

I've been off VB for several years now, but to solve a problem in another language, I'm forced to develop a wrapper in this one. I have a factory method to dynamically create and return an object of a type based on input from elsewhere. The provided input is meant to be the class name from which to create an object from. Normal syntax means that the entire class has to be explicitly spelled out. To do it this way, there could literally be hundreds of if/then's or cases to handle all the available class/object choices within the referenced libs:

我已经离开 VB 好几年了,但是为了用另一种语言解决问题,我不得不用这种语言开发一个包装器。我有一个工厂方法,可以根据其他地方的输入动态创建和返回一个类型的对象。提供的输入是用来创建对象的类名。正常语法意味着必须明确说明整个类。要这样做,实际上可能有数百个 if/then 或 case 来处理引用库中所有可用的类/对象选择:

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

I'm hoping instead to reduce all this case handling to a single line: IE...

我希望将所有这些案例处理减少到一行:IE ...

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

In PHP, this is handled like so...

在 PHP 中,这是这样处理的......

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

Edit:Looking at some of the answers, I think I'm in way over my head here. I did manage to get it working using this CreateInstancemethod variation of the Assembly class, even though I'm more interested in this variation giving more options, including supplying construct parameters...

编辑:查看一些答案,我想我在这里不知所措。我确实设法使用Assembly 类的这个 CreateInstance方法变体让它工作,尽管我对这个变体更感兴趣,提供更多选项,包括提供构造参数......

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 other words, it takes a method to do this, and not any inherent language syntax? This Activator variationalso worked when the full assembly string and class path is used. I'm suspicious CreateInstance may not have the full ability to let me treat objects as if they were called normally, ie obj = new System.Windows.Forms.Button. This is why I can't use simply CreateObject. If there is no natural language feature allowing you to substitute a class name for a string, does anyone have any insight into what sort of limitations I can expect from using CreateInstance?

换句话说,它需要一种方法来做到这一点,而不是任何固有的语言语法? 当使用完整的程序集字符串和类路径时,此 Activator 变体也有效。我怀疑 CreateInstance 可能没有完全的能力让我将对象视为正常调用,即obj = new System.Windows.Forms.Button. 这就是为什么我不能简单地使用CreateObject. 如果没有允许您用类名替换字符串的自然语言功能,有没有人了解我可以期望使用的限制类型CreateInstance

Also, is there even a difference between basic Activator.CreateInstance (after Unwrap) and Assembly.CreateInstance methods?

另外,基本的 Activator.CreateInstance(在 Unwrap 之后)和 Assembly.CreateInstance 方法之间甚至有区别吗?

回答by Tahbaza

This will likely do what you want / tested working; switch the type comment at the top to see.

这可能会做你想要/测试的工作;切换顶部的类型注释以查看。

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

回答by Conrad Frix

I'm pretty sure Activator is used for remoting. What you want to do is use reflection to get the constor and invoke it here's an example http://www.eggheadcafe.com/articles/20050717.asp

我很确定 Activator 用于远程处理。你想要做的是使用反射来获取常量并调用它,这是一个例子http://www.eggheadcafe.com/articles/20050717.asp

EDIT: I was misguided about Activator until jwsample corrected me.

编辑:在 jwsample 纠正我之前,我对 Activator 产生了误导。

I think the problem your having is that your assembly is the one that GetType is using to try and find Button. You need to call it from the right assembly.

我认为您遇到的问题是您的程序集是 GetType 用来尝试查找 Button 的程序集。您需要从正确的程序集中调用它。

This should do it

这应该做

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"))

回答by jwsample

Take a look at the Activator.CreateInstance(Type) method.

看看 Activator.CreateInstance(Type) 方法。

If your input is the name of a class you should be able do this:

如果您的输入是类的名称,您应该可以这样做:

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

You'll have to fiddle with the GetType call to make sure you give it enough information but for most cases just the name of the class should work.

您将不得不摆弄 GetType 调用以确保为其提供足够的信息,但在大多数情况下,只需提供类的名称即可。

回答by Guest

Here is a really easy way I have found while rummaging through the internet:

这是我在互联网上翻找时发现的一个非常简单的方法:

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