使用 vba 中的自定义对象键访问字典中的项目

Acces an item in a dictionary with a custom object key in vba

我在 vba.

中访问字典中的项目时遇到问题

我有以下字典:

Dim CResults as dictionary

我添加项目:

CResults.add currentkey, result

Currentkey 是我自己从一个名为 DCRkey

的 class 创建的对象
Private loadcase as long
Private csystem as String
Private node as long

result 是来自 class 的另一个对象 DCR:

Private Fs as double
Private C1 as double
Private C2 as double
...

然后我尝试使用

访问一个项目
Dim accesskey as DCRKey
accesskey.loadcase=10
accesskey.node = 2000
accesskey.csystem="Global"
Sheets("Results").cells(i,1).value= CResults(accesskey).C1

这就是我遇到错误的地方:runtime error 424 object required

然后我想也许我搜索的键和项目没有导入,所以我决定在 excel 作品sheet:

上显示我的整个词典
Dim testkey as variant
dim i as integer
i=1
with worksheet("Test")
    For each testkey in CResults.keys
        .cells(i,1)=test.node
        .cells(i,2)=test.loadcase
        .cells(i,3)=test.csystem
        .cells(i,4)=Cresults(testkey).C1
        .cells(i,5)=Cresults(testkey).Fs
        if accesskey.loadcase=testkey.loadcase and accesskey.node=testkey.node and accesskey.csystem=testkey.csystem then
            Msgbox "This key is the same as the accesskey"
        End if
        i=i+1
    Next
End with

我看到的是:

  1. 我之前搜索的关键字存在于字典中:视觉检查 sheet
  2. 我之前搜索的关键字确实存在于字典中:"This key is the same as the acceskey"显示一次
  3. for each 循环访问字典中的项目是有效的,因为 C1 和 Fs 在作品上正确显示sheet

然后我想可能是因为 testkey 被定义为变体而不是 DCRKey,所以我试了一下:

dim a as variant
Set a = currentkey
.Cells(i,1) = CResults(a).C1

但它不起作用,我仍然得到 runtime error 424

我也试过:

CResults.exists(accesskey)

它 returns 错误并在字典中创建一个新条目(顺便说一句,我讨厌这样做),使用与 acceskey 相同的键和一个空项目。

所以我的问题是:为什么使用自定义类型键访问项目在 for each 循环中起作用,而不是在独立调用中起作用。我错过了什么?这段代码与我编写的代码非常相似但不完全相同(为了让您更好地理解)。告诉我您是否认为真正的代码可以提供帮助。 感谢您的帮助。

您需要记住,class 的两个实例不是同一个实例,即使它们的所有属性都设置为相同的值。

让我们考虑以下示例:

Sub compareSimilarObjects()

    Dim key1 As DCRKey
    Dim key2 As DCRKey

    Set key1 = New DCRKey
    With key1
        .loadcase = 10
        .node = 2000
        .csystem = "Global"
    End With

    Set key2 = New DCRKey
    With key1
        .loadcase = 10
        .node = 2000
        .csystem = "Global"
    End With


    'Debug.Print to check pointer assigne to those variables.
    Debug.Print "Key1: " & ObjPtr(key1)
    Debug.Print "Key2: " & ObjPtr(key2)

End Sub

在此示例中,DCRKey class 的两个对象都将所有属性设置为相同的值。但是,它们与您在下面的代码 运行 Debug.Prints 最后看到的不是同一个对象。

在那些Debug.Print VBA中使用了内置函数ObjPtr。这个函数的目的是将return指针指向给定的对象。每个对象实例都有自己唯一的指针,因此如果下面的代码打印出两个不同的指针,则表示这些对象不相同。


现在,让我们考虑另一个例子:

Sub compareSimilarObjects()
    Dim key1 As DCRKey
    Dim key2 As DCRKey

    Set key1 = New DCRKey
    With key1
        .loadcase = 10
        .node = 2000
        .csystem = "Global"
    End With

    Set key2 = key1


    'Debug.Print to check pointer assigned to those variables.
    Debug.Print "Key1: " & ObjPtr(key1)
    Debug.Print "Key2: " & ObjPtr(key2)
    'Now those pointers should be the same.

End Sub

在这里,我们将 class DCRKey 的新实例分配给变量 key1,然后我们将相同的对象分配给变量 key2。现在 ObjPtr 应该 return key1key2 的值相同,因为这是同一个对象,它只是分配给两个不同的变量。


现在,让我们回到字典。

字典查找 Object 类型的键的方式是通过它的指针。

所以如果你想在字典中查找以对象为键添加的条目,你需要使用完全相同的对象(而不是具有相同属性的对象)。

示例:

Sub objectsToDictionaryTest()
    Dim CResults As Dictionary
    Dim accessKey As DCRKey
    Dim key As DCRKey
    Dim value As DCR
    '--------------------------------------------------------------------------------


    Set CResults = New Scripting.Dictionary


    'Let's create an object of [DCRKey] class (it will be used as a key when adding to
    'the dictionary) and an object of [DCR] class (it will be used as a value).
    Set accessKey = New DCRKey
    With accessKey
        .loadcase = 10
        .node = 2000
        .csystem = "Global"
    End With

    Set value = New DCR
    With value
        .C1 = 10
        .C2 = 20
        .Fs = 3
    End With


    'Now, let's add a new entry to the dictionary [CResults]
    CResults.Add accessKey, value


    'Let's create the other object of [DCRKey] that have exactly the same properties
    'as object assigned to the variable [accessKey].
    Set key = New DCRKey
    With key
        .loadcase = 10
        .node = 2000
        .csystem = "Global"
    End With



    'Now, let's check how dictionary is acting when we try to find an entry by [accesKey] and [key].
    Debug.Print "[accessKey] exists: " & CResults.Exists(accessKey)         'it should return True.
    Debug.Print "[key] exists: " & CResults.Exists(key)                     'it should return False.

    Debug.Print "[Value for accessKey]: " & CResults.Item(accessKey).Fs     'it should print 3

    'The line below should cause an run-time error 424: Object required.
    Debug.Print "[Value for key]: " & CResults.Item(key).Fs


End Sub