Excel 使用类的文本名称创建新对象
有没有办法通过使用类的文本名称将对象设置为类的新实例 我将有一个类库,根据其他变量,我希望在运行时获得其中一个类 例如,我有“CTest1”、“CTest2”、“CTest3” 我将有类似于下面的功能Excel 使用类的文本名称创建新对象,excel,vba,Excel,Vba,有没有办法通过使用类的文本名称将对象设置为类的新实例 我将有一个类库,根据其他变量,我希望在运行时获得其中一个类 例如,我有“CTest1”、“CTest2”、“CTest3” 我将有类似于下面的功能 Function GetTestClass(lngClassNo as long) as Object Dim strClassName as String strClassName = "CTest" & CStr(lngClassNo) Set GetTestCla
Function GetTestClass(lngClassNo as long) as Object
Dim strClassName as String
strClassName = "CTest" & CStr(lngClassNo)
Set GetTestClass = New instance of class(strClassName)
End Function
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
除非是这样,否则CTest类是在COM DLL中定义的,在这种情况下,可以使用CreateObject语句。您需要使用VB6来创建这样的DLL,但不能在Excel、Access等中创建DLL
Function GetTestClass(lngClassNo as long) as Object
Set GetTestClass = CreateObject("MyDll.CTest" & lngClassNo)
End Function
VB类定义实际上是在幕后定义COM接口,因此可以使用关键字将数据类型定义为抽象接口定义和具体实现 要获得任何类型的多态性,您必须这样做,否则您将在铸造方面遇到问题。用VB实现这一点有点复杂,但在技术上是可能的。如果你想深入研究,可以找到丹·阿普尔曼或马修·库尔兰的一些高级VB书籍。我不确定它们是否还在印刷,但它们可能通过亚马逊市场提供
这适用于VB6,我相当肯定它适用于VBA 您可以使用集合类或对象数组来完成此操作。所有对象都在一个数组中 在您的类中有一个.Name属性,当您创建该属性的实例时,请执行以下操作:
Dim CTest() as New CTest
For n = 1 to 10
Redim Preserve CTest(n)
CTest(n).Name = "CTest" & CStr(n)
Next l
又快又脏。上面的示例将在单个对象数组中返回10个CTest对象。您也可以放弃.Name而只使用CTest(n)。您可以使用元编程来实现这一点,尽管它看起来确实是一个相当复杂的问题。 下面是一个使用两个辅助函数的示例(为简洁起见省略):
CallByName
函数可以帮助您。假设您的项目中有一些类模块:clsSample0
、clsSample1
和clsSample2
。添加名为clsSpawner
的新类模块,该模块将所有目标类列为具有相同名称的公共变量,并使用new
关键字声明:
Public clsSample0作为新的clsSample0
公共clsSample1作为新clsSample1
公共clsSample2作为新clsSample2
在标准模块中添加函数Spawn()
代码:
函数生成(sClassName)作为对象
Set Spawn=CallByName(新的clsSpawner、sClassName、VbGet)
端函数
使用以下代码进行测试:
Sub TestSpawn()
作为对象的Dim objSample0a
作为对象的Dim objSample0b
作为对象的Dim objSample1
作为对象的Dim objSample2
设置objSample0a=Spawn(“clsSample0”)
设置objSample0b=Spawn(“clsSample0”)
设置objSample1=Spawn(“clsSample1”)
设置objSample2=Spawn(“clsSample2”)
调试。打印TypeName(objSample0a)'clsSample0
调试。打印TypeName(objSample0b)'clsSample0
调试。打印objSample0a为objSample0b'假
调试。打印TypeName(objSample1)“clsSample1”
调试。打印TypeName(objSample2)'clsSample2
端接头
它是如何工作的
Spawn
函数实例化clsSpawner
并调用clsSpawner
实例以返回请求的属性,实际上,clsSpawner
instance由于使用new
关键字声明而创建了目标类的一个新实例,并返回了引用。我认为如果您试图返回一个对象,可能会遇到强制转换问题。你必须用COM接口做点什么。哦,好吧。我从上面的一个精选案例开始,但希望有更干净的东西……而不是世界末日。ThanksVBA允许后期绑定,因此就我所见,没有强制转换问题,您只需要小心避免运行时错误,因为编译器不会在方法名等中发现任何拼写错误。这是实现建议的唯一两种方法。相关人员的接口建议将简化一些实现问题(我经常为此目的使用接口),因此您可以以多态方式保留编译时类型检查。但是,您仍然可以使用对象实例对函数调用使用运行时绑定。能够使用这个界面真是太好了。只是遗憾不得不使用精选案例…非常好。它确实有用,谢谢。很高兴能够使用编译器,而不必担心打字错误等。实现只是强制您实现给定类的所有公共方法/属性。这对按名称创建类有什么帮助?创建一个对象是不需要动脑筋的。问题不是创建类,而是不频繁地使用它。您可以使用对象和后期绑定,并希望获得最佳效果。实现为您提供类型安全多态性。感谢您提供的解决方案。不完全清楚在哪里添加Spawn()函数,但我知道了。我想知道为什么答案仍然没有任何响应。@AlexL我为Spawn()
函数添加了标准模块位置。
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