Excel 使用类的文本名称创建新对象

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

有没有办法通过使用类的文本名称将对象设置为类的新实例

我将有一个类库,根据其他变量,我希望在运行时获得其中一个类

例如,我有“CTest1”、“CTest2”、“CTest3”

我将有类似于下面的功能

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