VBA 中的动态属性名称

Posted

技术标签:

【中文标题】VBA 中的动态属性名称【英文标题】:Dynamic property names in VBA 【发布时间】:2011-01-26 13:13:04 【问题描述】:

我在 VBA (Access) 中有一个自定义类模块,它应该处理大量外部数据。目前我有两个函数Read(name)Write(name, value) 允许读取和设置动态属性。

有没有一种方法可以定义一种更符合语法的方式来读取和写入这些数据?我知道 VBA 中的某些对象具有访问数据的特殊方式,例如 RecordSet,它允许使用 myRS!property_name 读取和设置数据。有没有办法对自定义类模块做同样的事情?

【问题讨论】:

【参考方案1】:

感叹号语法用于访问Scripting.Dictionary 实例的成员(您需要先通过工具> 引用添加对Microsoft Scripting Runtime 的引用)。要使用这种语法,您需要将信息内部存储在字典中。

在类中使用它的最快方法是给你的类一个Scripting.Dictionary类型的对象变量,并如下设置:

Option Explicit

Dim d As Scripting.Dictionary

Private Sub Class_Initialize()
    Set d = New Scripting.Dictionary
End Sub

Private Sub Class_Terminate()
    Set d = Nothing
End Sub

Public Property Get IntData() As Scripting.Dictionary
    Set IntData = d
End Property

现在您可以使用 myinstance.IntData!MyProperty = 1... 访问属性,但要到达您想要的位置,您需要使用 Charlie Pearson's technique 将 IntData 设为您班级的默认成员。

完成后,您可以使用以下语法:

Dim m As MyClass
Set m = New MyClass

Debug.Print "Age = " & m!Age ' prints: Age = 
m!Age = 27
Debug.Print "Age = " & m!Age ' prints: Age = 27
Set m = Nothing

【讨论】:

好的,到目前为止,谢谢.. 但是有什么方法可以在没有基础字典/集合的情况下使用它?我的数据来自一个 XML 文件,我想使用的索引键部分基于路径。 如果您的 XML 库将相关节点的内容公开为字典,您可以定义一个返回该字典的属性并将该属性设为默认成员;如果它有点复杂,您可以尝试创建一个字典映射属性到 XPath 到特定实例。这种技术非常依赖字典或集合。【参考方案2】:

好的,感谢 Alain 和 KyleNZ,我现在找到了一种可行的方法来做到这一点,而下面没有集合或可枚举的对象。

基本上,多亏了 !运算符,我发现,通过 bang/pling 运算符进行的访问等同于访问对象的默认成员。如果属性Value 是我的类模块的默认成员,那么有三个等效语句可以访问该属性:

obj.Value("param")
obj("param")
obj!param

因此,要为自定义类模块制作简短的语法,只需定义一个默认成员即可。例如,我现在使用了以下Value 属性:

Property Get Value(name As String) As String
    Value = SomeLookupInMyXMLDocument(name)
End Property

Property Let Value(name As String, val As String) As String
    SetSomeNodeValueInMyXMLDocument(name, val)
End Property

通常,您现在可以像这样访问它:

obj.Value("foo") = "New value"
MsgBox obj.Value("foo")

现在要使该属性成为默认成员,您必须在属性定义中添加一行:

Attribute Value.VB_UserMemId = 0

所以,我最终得到了这个:

Property Get Value(name As String) As String
Attribute Value.VB_UserMemId = 0
    Value = SomeLookupInMyXMLDocument(name)
End Property

Property Let Value(name As String, val As String) As String
Attribute Value.VB_UserMemId = 0
    SetSomeNodeValueInMyXMLDocument(name, val)
End Property

然后,这可以工作并且等效于上面显示的代码:

obj("foo") = "New value"
MsgBox obj("foo")

' As well as
obj!foo = "New value"
MsgBox obj!foo

' Or for more complex `name` entries (i.e. with invalid identifier symbols)
obj![foo] = "New value"
MsgBox obj![foo]

请注意,除了 Microsoft Office 附带的 VBA 编辑器之外,您必须在其他编辑器中添加 Attribute Value.VB_UserMemId = 0,因为该编辑器由于某种原因隐藏了 Attribute 指令。您可以轻松导出模块,在其中打开它记事本,添加指令,然后将其导入 VBA 编辑器。只要您不对默认成员进行太多更改,就不应删除该指令(只需确保不时在外部编辑器中检查即可)。

【讨论】:

【参考方案3】:

查看其他问题:Bang Notation and Dot Notation in VBA and MS-Access

bang 运算符 (!) 是 访问集合的成员或 其他可枚举对象

如果您让您的类扩展 VBA 中的 Collection 类,那么您应该能够利用这些运算符。以下问题是扩展集合类的用户的示例: Extend Collections Class VBA

【讨论】:

以上是关于VBA 中的动态属性名称的主要内容,如果未能解决你的问题,请参考以下文章

VBA的对象方法属性

按街道名称排列的 VBA 组属性

如何从父类中的名称动态设置属性?

流类型对象中的动态属性名称

[Excel VBA] Shape.Type属性名称及对应值列表

使用 VBA 从主窗体设置子窗体上的窗体属性