VBA 中的动态属性名称

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4804947/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 12:34:09  来源:igfitidea点击:

Dynamic property names in VBA

classvbaproperties

提问by poke

I have a custom class module in VBA (Access) that is supposed to handle a large amount of external data. Currently I have two functions Read(name)and Write(name, value)that allows to read and set dynamic properties.

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

Is there a way to define a more syntactic way to read and write those data? I know that some objects in VBA have a special way of accessing data, for example the RecordSet, which allows to read and set data using myRS!property_name. Is there a way to do exactly the same for custom class modules?

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

采纳答案by poke

Okay, thanks to Alain and KyleNZ I have now found a working way to do this, without having a collection or enumerable object below.

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

Basically, thanks to the name of the ! operator, I found out, that access via the bang/pling operator is equivalent to accessing the default member of an object. If the property Valueis the default member of my class module, then there are three equivalent statements to access that property:

基本上,这要归功于 ! 我发现,通过 bang/pling 操作符访问相当于访问对象的默认成员。如果属性Value是我的类模块的默认成员,那么有三个等效的语句来访问该属性:

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

So to make a short syntax working for a custom class module, all one has to do is to define a default member. For example, I now used the following Valueproperty:

因此,要为自定义类模块创建一个简短的语法,您所要做的就是定义一个默认成员。例如,我现在使用了以下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

Normally, you could now access that like this:

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

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

Now to make that property the default member, you have to add a line to the Property definition:

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

Attribute Value.VB_UserMemId = 0

So, I end up with this:

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

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

And after that, this works and equivalent to the code shown above:

之后,这将起作用并等效于上面显示的代码:

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]

Note that you have to add the Attribute Value.VB_UserMemId = 0in some other editor than the VBA editor that ships with Microsoft Office, as that one hides Attributedirectives for some reason.. You can easily export the module, open it in notepad, add the directives, and import it back in the VBA editor. As long as you don't change too much with the default member, the directive should not be removed (just make sure you check from time to time in an external editor).

请注意,您必须Attribute Value.VB_UserMemId = 0在 Microsoft Office 附带的 VBA 编辑器之外的其他编辑器中Attribute添加回到 VBA 编辑器。只要您不对默认成员进行太多更改,就不应删除该指令(只需确保不时在外部编辑器中进行检查)。

回答by KyleNZ

The exclamation mark syntax is used to access members of a Scripting.Dictionaryinstance(you'll need to add a reference to Microsoft Scripting Runtimethrough Tools > References first). To use this syntaxyou'll need to be storing the information internally in a dictionary.

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

The quickest way to use it in a class is to give your class an object variable of type Scripting.Dictionaryand set it up as follows:

在类中使用它的最快方法是为您的类提供一个类型为对象的变量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

Now you can access properties using myinstance.IntData!MyProperty = 1... but to get to where you want to be you need to use Charlie Pearson's techniquefor making IntDatathe default member for your class.

现在您可以使用myinstance.IntData!MyProperty = 1...访问属性,但要到达您想要的位置,您需要使用Charlie Pearson 的技术IntData为您的类创建默认成员。

Once that's done, you can use the following syntax:

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

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

回答by Alain

See this other question: Bang Notation and Dot Notation in VBA and MS-Access

看到另一个问题:Bang Notation and Dot Notation in VBA and MS-Access

The bang operator (!) is shorthand for accessing members of a Collection or other enumerable object

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

If you make your class extend the Collection class in VBA then you should be able to take advantage of those operators. In the following question is an example of a user who extended the collection class: Extend Collections Class VBA

如果您让您的类扩展 VBA 中的 Collection 类,那么您应该能够利用这些运算符。下面的问题是一个用户扩展集合类的例子: 扩展集合类 VBA