Is there a way to set an object to the new instance of a class by using the text name of the class?
I will have a library of classes, and depending on some other variable, I want to get one of these classes at runtime.
E.g. I have “CTest1”, “CTest2”, “CTest3”
I would have function similar to the below
Function GetTestClass(lngClassNo as long) as Object Dim strClassName as String strClassName = "CTest" & CStr(lngClassNo) Set GetTestClass = New instance of class(strClassName) End Function
There’s no reflection in VBA, so I don’t think this is possible. You’d have to do something like the following I’m afraid:
Function GetTestClass(lngClassNo as long) as Object Select Case lngClassNo Case 1 Set GetTestClass = New CTest1 Case 2 Set GetTestClass = New CTest2 ... End Select End Function
Unless that is your CTest classes are defined in a COM DLL, in which case you could use the CreateObject statement. You would need to use VB6 to create such a DLL though, you can’t create DLLs in Excel, Access, etc.
Function GetTestClass(lngClassNo as long) as Object Set GetTestClass = CreateObject("MyDll.CTest" & lngClassNo) End Function
You can use metaprogramming to do this, although it does seem like quite a hack.
Here is an example that uses a couple of helper functions (omitted for brevity):
Public Function CreateInstance(typeName As String) As Object Dim module As VBComponent Set module = LazilyCreateMPCache() If Not FunctionExists(typeName, module) Then Call AddInstanceCreationHelper(typeName, module) End If Dim instanceCreationHelperName As String instanceCreationHelperName = module.name & ".GetInstanceOf" & typeName Set CreateInstance = Application.Run(instanceCreationHelperName) End Function Sub AddInstanceCreationHelper(typeName As String, module As VBComponent) Dim strCode As String strCode = _ "Public Function GetInstanceOf" & typeName & "() As " & typeName & vbCrLf & _ "Set GetInstanceOf" & typeName & " = New " & typeName & vbCrLf & _ "End Function" Call AddFunction(strCode, module) End Sub
VB class definitions are really defining COM interfaces behind the scenes, so one can define data types as an abstract interface definition with concrete implementations using the implements keyword.
To get any sort of polymorphism you have to do this, otherwise you will have problems with casting. It is somewhat fiddly but technically possible to do this with VB. If you want to dig into it find some of the advanced VB books by Dan Appleman or Matthew Kurland. I’m not sure if they’re still in print but they’re probably available through Amazon Marketplace.
This works with VB6 and I’m fairly sure it works with VBA.
CallByName function can help you. Let’s say there are some class modules in your project:
clsSample2. Add a new class module named
clsSpawner, which lists all target classes as public variables having the same names, and declared with
Public clsSample0 As New clsSample0 Public clsSample1 As New clsSample1 Public clsSample2 As New clsSample2
In a standard module add
Function Spawn() code:
Function Spawn(sClassName) As Object Set Spawn = CallByName(New clsSpawner, sClassName, VbGet) End Function
Test it with some code like this:
Sub TestSpawn() Dim objSample0a As Object Dim objSample0b As Object Dim objSample1 As Object Dim objSample2 As Object Set objSample0a = Spawn("clsSample0") Set objSample0b = Spawn("clsSample0") Set objSample1 = Spawn("clsSample1") Set objSample2 = Spawn("clsSample2") Debug.Print TypeName(objSample0a) ' clsSample0 Debug.Print TypeName(objSample0b) ' clsSample0 Debug.Print objSample0a Is objSample0b ' False Debug.Print TypeName(objSample1) ' clsSample1 Debug.Print TypeName(objSample2) ' clsSample2 End Sub
How does it work?
Spawn function instantiates
clsSpawner and calls the
clsSpawner instance to return requested property, and actually
clsSpawner instance creates a new instance of the target class due to declaration with
New keyword and returns the reference.
You might be able to do it with a collection class or object array. All the objects are in one array.
In your class have a .Name property and when you create an instance of it do this:
Dim CTest() as New CTest For n = 1 to 10 Redim Preserve CTest(n) CTest(n).Name = "CTest" & CStr(n) Next l
Quick and dirty. The above example would return 10 CTest objects in a single object array. You could also ditch the .Name and just use CTest(n).