VBA如何直接访问字典键元素

3

上下文

在VBA中,您可以创建并填充字典,例如:

    Dim oDict As Object
    Set oDict = CreateObject("Scripting.Dictionary")
    oDict("key 1") = "value 1"
    oDict("key 2") = "value 2"
    oDict("key 3") = "value 3"

使用Keys方法,您可以将键作为数组获取:

返回包含字典对象中所有现有键的数组。

    Dim aKeys() As Variant
    aKeys = oDict.Keys
    Debug.Print VarType(aKeys)       ' prints "8204"
    Debug.Print VarType(oDict.Keys)  ' prints "8204"

问题

但是当我直接访问其中一个键时,会出现这个神秘的错误信息:

    Debug.Print aKeys(2)       ' prints "key 3"
    Debug.Print oDict.Keys(2)  ' Run-time error '451':
                               ' Property let procedure not defined 
                               ' and property get procedure did not 
                               ' return an object

解决失败的尝试

虽然上述是我不理解的主要行为,但以下是处理oDict.Keys作为数组的所有尝试的完整列表:

Option Explicit

Public Function ArrayGet(ByRef aArray() As Variant, i As Integer) As Variant
    ArrayGet = aArray(i)
End Function

Public Function ArrayWrap(ByRef aArray() As Variant) As Variant()
    ArrayWrap = aArray
End Function

Public Sub TEST()

    Dim oDict As Object
    Set oDict = CreateObject("Scripting.Dictionary")
    oDict("key 1") = "value 1"
    oDict("key 2") = "value 2"
    oDict("key 3") = "value 3"

    Dim aKeys() As Variant
    aKeys = oDict.Keys

    Debug.Print VarType(aKeys)           ' prints "8204"
    Debug.Print VarType(oDict.Keys)      ' prints "8204"

    Debug.Print aKeys(2)                 ' prints "key 3"
    'Debug.Print oDict.Keys(2)            ' Run-time error '451': Property let procedure not defined and property get procedure did not return an object
    'Debug.Print oDict.Keys.Get(2)        ' Run-time error '424': Object required
    'Debug.Print oDict.Keys.Item(2)       ' Run-time error '424': Object required

    Debug.Print ArrayGet(aKeys, 2)       ' prints "key 3"
    'Debug.Print ArrayGet(oDict.Keys, 2)  ' Compile error : Type mismatch: array or user-defined type expected

    'Debug.Print Array(aKeys)(2)          ' Run-time error '9'  : Subscript out of range
    'Debug.Print Array(oDict.Keys)(2)     ' Run-time error '9'  : Subscript out of range

    Debug.Print ArrayWrap(aKeys)(2)      ' prints "key 3"
    'Debug.Print ArrayWrap(oDict.Keys)(2) ' Compile error : Type mismatch: array or user-defined type expected

    Dim key As Variant

    For Each key In aKeys
        Debug.Print key                  ' prints "key 1", "key 2" and "key 3"
    Next key

    For Each key In oDict.Keys
        Debug.Print key                  ' prints "key 1", "key 2" and "key 3"
    Next key

End Sub

注:从 OP 写问题的过程中,我找到了答案。希望这个问题中包含的关键词能让其他人更快地找到解决方案。 - pjvleeuwen
注意:现在已经知道了原因,很容易看出这是与此处所述的根本问题相同(链接:https://dev59.com/mqfja4cB1Zd3GeqPqhtU#47532267)。 - pjvleeuwen
2个回答

8

出了什么问题

    Debug.Print oDict.Keys(2)  ' Run-time error '451':
                               ' Property let procedure not defined 
                               ' and property get procedure did not 
                               ' return an object
Keys 是一个方法名。虽然 VBA 允许您在不提供参数时省略括号,但它仍然是一个方法。如果在其后指定括号,则内容将传递给该方法。Keys 方法不接受整数参数。

如何修复

通过显式提供 Keys 方法的括号(例如 Keys()),我们可以直接应用 / 跟随括号以访问数组元素。
根据问题中的示例:以下两个替代方案是等效的:
    Debug.Print aKeys(2)         ' prints "key 3"
    Debug.Print oDict.Keys()(2)  ' prints "key 3"

2
谢谢你分享你的发现。这个问题困扰了我很多年...我通常在立即窗口中检查我的字典和字典的字典,而今天发生的最好的事情就是这个...天啊...谢谢!!! - Nay Lynn

3
如果你不添加对Microsoft Scripting Runtime的引用,你需要使用后期绑定来使用字典对象。使用后期绑定,你会失去一些功能。如果你尝试通过索引访问字典的键,则会抛出运行时错误451。

enter image description here

如果您通过VBE的工具,引用中添加了Microsoft Scripting Runtime库引用,则现在可以直接通过其序数索引号访问字典的键。

enter image description here

Sub test3()

    Dim i As Long, dict As New Scripting.dictionary

    dict.Add Key:="key1", Item:="item1"
    dict.Add Key:="key2", Item:="item2"
    dict.Add Key:="key3", Item:="item3"

    For i = LBound(dict.Keys) To UBound(dict.Keys)
        Debug.Print dict.Keys(i)
    Next i

End Sub

'results
key1
key2
key3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接