如何将类名作为参数传递?

Igo*_*kov 5 vba

我想创建一个函数,它接受一个类示例/类名称并返回一定数量的所述类的示例的集合,初始化和填充。到目前为止,我已经提出了这个解决方案:

Function getCollectionObj(className as string) As Collection

    Dim obj As Variant
    Dim result As Collection
    Dim objType As String
    Dim I 
    
    For I = 1 To 5
    
    'selecting the type of a class based on string name
    Select Case className
    Case "Cls1"
        Set obj = New Cls1
    Case "Cls2"
        Set obj = New Cls2
    Case "DocumentStart"
        Set obj = New Cls3    
    End Select
    'some code handling the exemplar of the object.

    result.add obj
    Next I
    Set getCollectionObj = result
End Function
Run Code Online (Sandbox Code Playgroud)

这样做的问题是我必须明确地将每个类放入select case其中,并且代码每次都必须选择和声明 cerrain 类,即使集合中的所有对象都应该是同一类的范例。我该如何改进?

编辑:我的测试代码(给出“对象需要错误”)

主要模块:

Private Function getCollectionObj(ByVal factory As IObjectFactory) As Collection
Dim I
    For I = 1 To 5
    result.Add factory.Create
    Next I
End Function

Sub test()
Dim var As Object
Set var = getCollectionObj(New Class1ObjectFactory)
End Sub
Run Code Online (Sandbox Code Playgroud)

IObjectFactory 类:

Option Explicit
Public Function Create() As Object

End Function
Run Code Online (Sandbox Code Playgroud)

Cls1Factory 类(选择函数时,右侧下拉列表显示“创建”):

Option Explicit
Implements IObjectFactory

Private Function IObjectFactory_Create() As Object
     ' "Object required" error here
     Set IObjectFactory_Create = New Cls1
End Function
Run Code Online (Sandbox Code Playgroud)

Cls1 类:

Option Explicit
Public I As String
Run Code Online (Sandbox Code Playgroud)

Mat*_*don 8

理想情况下,您不会(回答标题中的问题) - 例如,当类被重命名时,您的代码不会无声地中断。

有一种更好的方法,一旦出现问题,它就会立即为您提供编译时错误,并且可以很好地与静态代码分析和重构工具(例如Rubberduck)配合使用- 完全公开,这是我的网站,我管理着 Rubberduck 打开-源项目。

您可以通过定义抽象工厂接口来形式化创建类实例的任务。添加一个新的类模块,调用它:IObjectFactory

Option Explicit
Public Function Create() As Object
End Function
Run Code Online (Sandbox Code Playgroud)

现在添加一个新的类模块,调用它Cls1Factory并使其实现抽象工厂接口:

Option Explicit
Implements IObjectFactory

Private Function IObjectFactory_Create() As Object
    Set IObjectFactory_Create = New Cls1
End Function
Run Code Online (Sandbox Code Playgroud)

添加一个新的类模块,调用它Cls2Factory并使其也实现抽象工厂接口:

Option Explicit
Implements IObjectFactory

Private Function IObjectFactory_Create() As Object
    Set IObjectFactory_Create = New Cls2
End Function
Run Code Online (Sandbox Code Playgroud)

添加另一个可以创建Cls3实例的实现,称之为Cls3Factory.

然后按如下方式更改函数的签名:

Public Function getCollectionObj(ByVal factory As IObjectFactory) As Collection
Run Code Online (Sandbox Code Playgroud)

现在整个Select Case块变成了这个单一的语句:

result.Add factory.Create
Run Code Online (Sandbox Code Playgroud)

用于执行此操作的调用代码:

Set things1 = getCollectionObj("Cls1")
Set things2 = getCollectionObj("Cls2")
Set things3 = getCollectionObj("Cls3")
Run Code Online (Sandbox Code Playgroud)

现在需要这样做:

Set things1 = getCollectionObj(New Cls1Factory)
Set things2 = getCollectionObj(New Cls2Factory)
Set things3 = getCollectionObj(New Cls3Factory)
Run Code Online (Sandbox Code Playgroud)

该函数现在可以创建您想要的任何类的 5 个实例的集合,根本不需要修改它:如果您需要支持一个新类,只需为它实现一个新工厂,然后将它作为参数传递给函数。


回复:编辑

Rubberduck 的静态代码分析可以帮助您避免大量陷阱,就像您编辑的代码段中的陷阱一样:未分配函数返回值,在初始化之前访问结果变量,等等:

OP 的修订版 2 代码受到小鸭审查

“需要对象”错误由其根本原因发出信号,此处按导致此特定错误的级联顺序:

  • 'Module1' 中未指定 'Option Explicit'。
  • 未声明局部变量“结果”。
  • 使用变量“result”但未分配。

Option Explicit未指定允许代码在result未声明的情况下执行。因为它没有被声明,所以它被分配为 aVariant/Empty直到它被分配......除非它从来没有,并且当一个成员调用 ( .Add) 临时针对该变体进行时,这就是 VBA在运行时尖叫并说“需要对象”的时候,因为该成员调用需要一个对象才能有效。但是 VBA 看到的只是一个Variant/Empty它刚刚在现场创建的指针。

运行时引发错误后,.Create工厂方法调用返回,但之前返回的对象作为参数传递给一个偶然后期绑定 .Add成员通话。执行没有进入.Add方法,VBA没有成功Collectionresult变量中解引用一个对象;但是因为调试器不允许我们单步执行操作符,所以当我们点击“DEBUG”时,我们会回到失败的语句上,并且整个result.Add factory.Create语句都被突出显示(而不是仅仅result.Add调用是这里实际失败的操作) .

因为在同一行上有两个语句,调试器并不完全处于它现在应该处于的确切状态。如果我们按下 F8,我们将被带回到工厂方法中,如果我们没有意识到发生了什么,那么很容易让调试器将我们带入调查完全正常的执行路径中。

分开声明:

Dim o As Object
Set o = factory.Create '<~ no problem here!

result.Add o '<~ object required
Run Code Online (Sandbox Code Playgroud)

现在调试器进入中断模式,并突出显示正确的失败语句。

为了完整起见,工作代码:

Option Explicit

Public Sub test()
    Dim var As Collection
    Set var = getCollectionObj(New Class1ObjectFactory)
    Debug.Print var.Count
End Sub

Private Function getCollectionObj(ByVal factory As IObjectFactory) As Collection
    Dim result As Collection
    Set result = New Collection
    Dim I As Long
    For I = 1 To 5
        result.Add factory.Create
    Next I
    Set getCollectionObj = result
End Function
Run Code Online (Sandbox Code Playgroud)