VBA 中没有任何机制可以让您通过名称检查类是否存在,如果存在则创建一个新实例。
但是,有可能实现。让我们剖析这些问题,看看我们如何解决这些问题。
问题 1
您需要创建一个您不确定当前项目中是否存在的类的实例。怎么样?
正如您已经尝试过的,Application.Run 和 CreateObject 不起作用。
Application.Run 只能在标准 .bas 模块(不是类模块)中运行方法。它不创建类的实例。
CreateObject 在幕后做了一些事情。首先,它使用您传递的 ProgID(字符串)调用CLSIDFromProgIDEx。然后,它调用CoCreateInstance。问题是 VBA 类在注册表中没有它们的 ProgID,因此 CreateObject 根本不起作用。您需要将您的课程放在 ActiveX.exe 的已注册 .dll 文件中才能完成这项工作。
剩下的就是New 关键字来实例化一个新的ClassBeta。这显然在类存在时有效,但在不存在时会给出“用户定义的类型未定义”编译器错误。只有 2 种方法可以抑制此编译器错误:
- 有一个编译器指令
- 根本没有
New ClassBeta
ClassAlfa 中的编译器指令如下所示:
Option Explicit
#Const BETA_EXISTS = False
Sub Test()
Dim myBeta As Object
#If BETA_EXISTS Then
Set myBeta = New ClassAlpha
#End If
Debug.Print "Type of 'myBeta' is: " & TypeName(myBeta)
End Sub
如果项目中没有ClassBeta,这编译得很好,但是你永远不能让BETA_EXISTSconditional compiler constant变成True,因为:
表达式中只能使用条件编译器常量和文字
因此,最后一个选项是不要在项目中的任何位置使用New ClassBeta。除了,我们这样做。我们可以把它放在ClassBeta本身作为一个工厂:
Option Explicit
Public Function Factory() As ClassBeta
Set Factory = New ClassBeta
End Function
当类丢失时,工厂丢失,New ClassBeta 不会抛出编译器错误。
问题 2
我们如何在ClassBeta 上调用.Factory 方法?
好吧,我们显然不能创建ClassBeta 的新实例,因为这是我们的第一个问题。
我们可以做的是确保ClassBeta 总是有一个默认的全局实例(就像用户表单一样)。为此,我们需要将类导出到 .cls 文本文件并使用文本编辑器(如记事本)对其进行编辑。文本应如下所示:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "ClassBeta"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit
Public Function Factory() As ClassBeta
Set Factory = New ClassBeta
End Function
请注意,我已将 VB_PredeclaredId 属性更改为 True(在文本编辑器中手动更改)。现在我们可以将类导入回来。我们可以通过在即时窗口中输入?Typename(ClassBeta.Factory) 然后按 Enter 来检查它是否有效。我们应该看到:
ClassAlfa 中的代码现在可以写成:
Option Explicit
Sub Test()
Dim myBeta As Object
On Error Resume Next
Set myBeta = ClassBeta.Factory
On Error GoTo 0
Debug.Print "Type of 'myBeta' is: " & TypeName(myBeta)
End Sub
问题 3
如果我们从项目中删除ClassBeta,以下行将无法编译:
Set myBeta = ClassBeta.Factory
但是,与问题1相比,这次编译器错误是'Variable not defined'。
我想摆脱这个新的编译器错误的唯一方法是关闭Option Explicit。是的!太糟糕了!
ClassAlfa:
'Option Explicit 'needs to be off to be able to compile without the ClassBeta class
Sub Test()
Dim myBeta As Object
On Error Resume Next
Set myBeta = ClassBeta.Factory
On Error GoTo 0
Debug.Print "Type of 'myBeta' is: " & TypeName(myBeta)
End Sub
最后的想法
您可以在 Option Explicit 开启时进行开发,然后为您的用户关闭它。
如果您的用户将使用ClassAlfa 并关闭Option Explicit,则代码应该可以正常工作。但如果他们也想要ClassBeta,那么他们获得它的唯一方法就是导入 .cls 文件。复制粘贴代码不起作用,因为它们会丢失ClassBeta 的全局实例(我们在VB_PredeclaredId 隐藏属性中设置的实例)。
我必须说我不建议删除Option Explicit,因为这可能会导致其他问题。我认为没有办法以“干净”的方式实现您想要的。