Excel 在字典中用作键时范围的奇怪行为

Excel 在字典中用作键时范围的奇怪行为,excel,vba,Excel,Vba,我有以下代码: Dim dicMyHash As Dictionary Dim rngMyRange As Range ' A1 is empty - although the outcome is the same in any case Set rngMyRange = Range("A1") Set dicMyHash = New Dictionary dicMyHash.Add Key:=rngMyRange(1), Item:=0 Debug.Print dicMyHash.Ex

我有以下代码:

Dim dicMyHash As Dictionary
Dim rngMyRange As Range

' A1 is empty - although the outcome is the same in any case
Set rngMyRange = Range("A1")
Set dicMyHash = New Dictionary

dicMyHash.Add Key:=rngMyRange(1), Item:=0

Debug.Print dicMyHash.Exists(rngMyRange(1).Value)   ' returns False
Debug.Print rngMyRange(1) = rngMyRange(1).Value     ' returns True
这种行为有些出乎意料。有什么类型的演员在幕后表演吗
rngMyRange(1).Value
属性返回一个
变量
,而
rngMyRange(1)
rngMyRange.项(1)
,它是一个
范围
。但是,将
rngMyRange(1)
转换为
变量
会得到相同的结果

此外,添加键是按值进行的(因此
rngMyRange(1)
的副本作为键传递)。但是我仍然不明白为什么
存在
没有找到密钥


提前谢谢你

我认为造成这种情况的原因是,
rngMyRange
被认为是一个二维数组,两个数组维度都被传递到字典中

如果将向字典中添加元素的行更改为此行:

dicMyHash.Add Key:=rngMyRange(1).value, Item:=0
它开始像您期望的那样工作-两个检查点都返回
true


调试代码时,您还可以在
本地窗口中分析这种情况。

我不确定您是如何使用它的,但这将返回
True

Sub test()
Dim dicMyHash As Dictionary
Dim rngMyRange As Range

Set rngMyRange = Range("A1")
Set dicMyHash = New Dictionary

dicMyHash.Add Key:=rngMyRange(1).Value, Item:=0 ' assign it with Value
Debug.Print dicMyHash.Exists(rngMyRange(1).Value)
End Sub
这样你就有了一个项目,它的密钥是A1中的任何东西


我认为,如果没有
,它将无法工作的原因是您正在为
分配一个
范围
。如果您将范围分配给字典的项,对我来说会更有意义。

因此,在这里,我们传递了三个不同的值:

  • 原始范围
  • 范围.Value
    ,它是一个变量
  • 词典内部的(1)的副本
  • 如果你把这些和等号比较,它们都是一样的。但是根据字典的说法,它们都是不同的

    为什么??对对象使用等号时,等号会强制对象调用其默认属性。
    Range
    的默认属性是
    Range.Value
    ,这就是为什么
    r=r.Value
    r=r.Offset(0,0)

    但对于一本字典来说,这并不聪明。想想看:每次调用
    Dictionary.Exists
    都会导致用作键的每个对象调用其默认属性。这可能会非常昂贵,而且可能会引发很多副作用。因此,
    Dictionary.Exists
    测试以下内容:

  • 你在比较一个对象和一个非对象吗?自动失败
  • 你在比较两个非项目吗?返回
    a=b
  • 你在比较两个物体吗?返回
    a是b
  • 因此
    r
    r.Value
    不同,因为一个是对象,另一个是非对象。如果您复制了
    r
    ,就像
    r.Offset(0,0)
    ,它们也不相同,因为它们仍然指向两个不同的对象,即使对象具有相同的内容

    另一方面,这将起作用,因为您将
    r
    制作成与
    d.Keys(0)
    相同的对象:


    嗨,KazJew,谢谢-关于尺寸的观点很好。是的,传递值确实有效。。但是,将所有出现的
    rngMyRange(1)
    替换为
    rngMyRange(1,1)
    仍然像以前一样返回
    false
    。好主意,重新设置
    Locals窗口
    ,将给它一个机会。因此,再次强调,传递
    rngMyRange(1,1)
    仍然被识别为数组,但
    rngMyRange(1,1)。值
    被识别为正确值,两个测试点的结果都是
    true
    。哦,好的,我明白了。我还注意到,
    .exists(rngMyrange(1,1))
    也给出了
    false
    。这是因为
    rngMyrange(1,1)
    作为二维数组复制到字典中吗?我宁愿说它没有正确地转换为从数组(1,1)维度获取值…嗨,道格,谢谢-我通常使用
    ,只是想知道为什么
    范围
    似乎不能作为
    键正常工作。还注意到,
    .Exists(rngMyRange(1))
    rngMyRange(1)
    键时返回false,并且想知道为什么会出现这种情况。。但是,是的,我会坚持使用
    value
    。我投了赞成票,理由是上面的答案提供了一个解决办法。谢谢-因为
    Dictionary.Exists
    可以像你上面描述的那样工作,其余的都是有意义的(并且在你的答案中设置
    r=d.Keys(0)
    )。不过,我还是会使用更合理的键,绝对像
    r.Address
    。在我的上下文中,我将自定义对象存储在该字典中,并使用它们的名称(字符串)作为键-我使用
    range.value
    (使用
    .exists
    检查重复项)从动态范围中获取。在某个时候,我引用了一个没有
    .value
    部分的键,结果遇到了麻烦。感谢您的详细解释-非常有用!
    Dim d As Scripting.Dictionary
    Dim r As Range
    Set r = [a1]
    Set d = New Dictionary
    d.Add r, 0
    Set r = d.Keys(0)
    Debug.Print d.Exists(r)