bob-the-destroyer
bob-the-destroyer

Reputation: 3154

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

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:

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...

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

In PHP, this is handled like so...

$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 CreateInstance method variation of the Assembly class, even though I'm more interested in this variation giving more options, including supplying construct parameters...

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 variation also 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?

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

Upvotes: 8

Views: 42003

Answers (4)

Guest
Guest

Reputation: 1

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

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

Upvotes: 0

Conrad Frix
Conrad Frix

Reputation: 52655

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

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

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.

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

Upvotes: 3

Tahbaza
Tahbaza

Reputation: 9548

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

Upvotes: 10

jwsample
jwsample

Reputation: 2411

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

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.

Upvotes: 0

Related Questions