VBA class 实例化和作用域

VBA class instantiation and scope

我想创建 class 作为配置管理和服务助手。它会在 XML 文件中存储一些基本的连接设置,将其读取到它自己的属性中,并服务于任何其他模块、表单、对象等。 我创建了一个 class,如下所示:

Option Compare Database
Option Explicit

Private mstrSqlServerName As String
'...


Public Property Get SqlServerName() As String
   SqlServerName = mstrSqlServerName
End Property
'...

Private Sub Class_Initialize()
    readConfigFile
End Sub

Private Function loadConfigFile() As MSXML2.DOMDocument60
On Error GoTo FunctionError
Dim XMLFileName As String
Dim objRoot As IXMLDOMElement
Dim strMsg As String
Dim oXMLFile As MSXML2.DOMDocument60
 
'Open the xml file
Set oXMLFile = New MSXML2.DOMDocument60
XMLFileName = (Application.CurrentProject.Path & "\config.xml")
With oXMLFile
    .validateOnParse = True
    .SetProperty "SelectionLanguage", "XPath"
    .async = False
    .Load (XMLFileName)
End With
    
Set loadConfigFile = oXMLFile

End Function


Public Sub readConfigFile()

    Dim oXMLFile As MSXML2.DOMDocument60
    
    Set oXMLFile = loadConfigFile

    mstrSqlServerName = oXMLFile.selectSingleNode("//config/database/SqlServerName").Text

End Sub

我已经在中级 window 中测试了我的 class 并且一切正常。然后 我创建了隐藏表单来实例化 class,如下所示:

'frmYouShouldNotSeeMe
Option Compare Database
Option Explicit

Public configuration As clsConfiguration

Private Sub Form_Load()

    Set configuration = New clsConfiguration
    MsgBox Prompt:=configuration.SqlServerName

End Sub

现在,从 other module/form/report 等我想调用配置项:

MsgBox configuration.SqlServerName

但是当我尝试编译我的项目时,它显示“编译错误,未定义变量”。简而言之:我找不到使用数据库其他对象的实例化(命名)对象属性的方法。他们只是不知道它的存在。在中间 window 一切正常,我可以实例化对象并调用 GET 函数。我做错了什么?可能这正是 OOP 设计带来的,我就是不明白。实现此目标的最佳方法是什么?

您可以向 class 添加两个 public 函数。

像这样:

Public Function SqlServerName() As String


  SqlServerName = oXMLFile.SelectSingleNode("//config/database/SqlServerName").Text


End Function

Public Function GetConfig(strNode As String, strValue As String) As String

  Dim strXPATH  As String
  strXMPATH = "//config/" & strNode & "/" & strValue
  
  
  GetConfig = oXMLFile.SelectSingleNode(strXMPATH).Text


End Function

现在在代码中您可以使用:

 Msgbox configuration.SqlServerName

或者要获得任何配置,您可以使用带有 2 个参数的辅助函数

Msgbox configuration("database","SqlServerName")

因此,class 的 public 成员必须由您编写。它不会通过“魔法”或突然暴露来自 class 的信息。您可以使用 public 函数,当您创建此类 public 函数时,它们将显示为 inteli-sense。 (它们成为 class 的属性)。因此,您的语法不起作用,因为您没有 public 函数(或 属性 get)来公开您想要的内容。您可以使用 属性 let/get,但是 public 函数也可以很好地工作,如上所示。

因此,要么为每个要公开的“事物”(节点)创建一个 public 函数,要么使用上面的辅助函数,您可以使用接受的函数传递键 + 节点值2个参数。以上两者都将成为 class 的一部分,在编码期间显示 inteli-sense - 您可以按照上述自由向 class 添加更多 public 成员。

#编辑

示例代码显示:

Set configuration = New clsConfiguration
MsgBox Prompt:=configuration.SqlServerName

需要这样:

dim configuration as New clsConfiuration
MsgBox Prompt:=configuration.SqlServerName

您可以在应用程序启动时设置一个称为配置的全局变量,因此不必在表单代码中声明配置变量。

因此您需要一个全局变量 - 在启动任何表单之前在您的启动代码中设置它。

所以在标准代码模块中,你需要这样:

Public configuration as new clsConfiguration

但是,您的代码屏幕截图缺少配置变量的创建。

你提供的代码是这样的:

Set configuration = New clsConfiguration
MsgBox Prompt:=configuration.SqlServerName

那么您是在何时何地将配置定义为全局范围变量的?

您要么必须对表单使用 LOCAL 范围(实际上是您的 on-load 事件)

dim configuration as New clsConfiuration
MsgBox Prompt:=configuration.SqlServerName

或者,您可以如前所述,在标准代码模块(不是表单模块,当然也不是 class 模块)中将“配置”声明为 public 全局变量。

如果你使用“new”关键字,那么你可以使用这个:

Public configuration as New clsConfiuration

以上内容可以放在任何标准代码模块中 - 它将是全局范围的。

有了上面,然后在表单加载事件中,这将起作用:

 MsgBox Prompt:=configuration.SqlServerName

由于在frmYouShouldNotSeeMe中声明了configuration,只要打开表格,您就可以参考表格来访问变量。

Debug.Print Forms("frmYouShouldNotSeeMe").configuration.SqlServerName