vba 使用类的文本名称创建一个新对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1057670/
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
Create a new object using the text name of the class
提问by MT.
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"
例如我有“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
回答by Patrick McDonald
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:
VBA 中没有反射,所以我认为这是不可能的。恐怕您必须执行以下操作:
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.
除非您的 CTest 类是在 COM DLL 中定义的,否则您可以使用 CreateObject 语句。您需要使用 VB6 来创建这样的 DLL,但您不能在 Excel、Access 等中创建 DLL。
Function GetTestClass(lngClassNo as long) as Object
Set GetTestClass = CreateObject("MyDll.CTest" & lngClassNo)
End Function
回答by Jordan
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
回答by omegastripes
CallByName
function can help you. Let's say there are some class modules in your project: clsSample0
, clsSample1
and clsSample2
. Add a new class module named clsSpawner
, which lists all target classes as public variables having the same names, and declared with New
keyword:
CallByName
功能可以帮助您。假设您的项目中有一些类模块:clsSample0
,clsSample1
和clsSample2
. 添加一个名为 的新类模块clsSpawner
,它将所有目标类列为具有相同名称的公共变量,并用New
关键字声明:
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()
代码:
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.
它是如何工作的?Spawn
函数实例化clsSpawner
并调用clsSpawner
实例以返回请求的属性,实际上clsSpawner
实例因New
关键字声明而创建目标类的新实例并返回引用。
回答by ConcernedOfTunbridgeWells
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 implementskeyword.
VB 类定义实际上是在幕后定义 COM 接口,因此可以使用implements关键字将数据类型定义为具有具体实现的抽象接口定义。
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.
要获得任何类型的多态性,您必须这样做,否则您将遇到转换问题。使用 VB 执行此操作有些繁琐,但在技术上是可行的。如果您想深入了解,请查找 Dan Appleman 或 Matthew Kurland 编写的一些高级 VB 书籍。我不确定它们是否仍在印刷中,但它们可能可以通过亚马逊市场获得。
This works with VB6 and I'm fairlysure it works with VBA.
这适用于VB6,我相当确信它的工作原理与VBA。
回答by mandroid
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:
在您的类中有一个 .Name 属性,当您创建它的实例时,请执行以下操作:
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).
又快又脏。上面的示例将在单个对象数组中返回 10 个 CTest 对象。您也可以放弃 .Name 并只使用 CTest(n)。