【问题标题】:VBA dictionary inheritance without link没有链接的VBA字典继承
【发布时间】:2015-01-16 05:12:44
【问题描述】:

我想让一个字典从另一个字典继承键和值。之后,如果我修改一个字典,它不会修改另一个。我认为这是直截了当的:

Sub testdic()
    Dim d
    Set d = CreateObject("Scripting.Dictionary")
    d.Add "first", 1
    Dim s
    Set s = d
    s.Add "second", 2
End Sub

上面的代码将键“second”和值 2 添加到 s 和 d 字典中,而我希望它只添加到 s 字典中。是否可以在不创建类的情况下做到这一点?

【问题讨论】:

标签: vba


【解决方案1】:

这是一个更通用的解决方案,它不限制您用于键或值的内容。该函数执行字典的“浅拷贝”。它返回一个新的字典对象,但原始字典中的任何对象本质上都是通过引用传递到新字典中的。

如果原始字典中的项目不是对象(字符串、整数等),这是一个有争议的问题。但是如果项目是对象,那么对在字典之间进行浅拷贝的任何对象的更改都会更改“两个”位置的对象(我将“两个”放在引号中,因为实际上只有一个对象,只有多个引用指向它)。

Function DictionaryShallowCopy(Dict As Object) As Object           ' <-- Late-bound
'Function DictionaryShallowCopy(Dict As Dictionary) As Dictionary  ' <-- Early-bound
    If Dict Is Nothing Then Exit Function

    Set DictionaryShallowCopy = CreateObject("Scripting.Dictionary") ' <-- Late-bound
    'Set DictionaryShallowCopy = New Dictionary                      ' <-- Early-bound
    If Dict.Count = 0 Then Exit Function

    Dim Key As Variant
    For Each Key In Dict.Keys
        DictionaryShallowCopy.Add Key, Dict.Item(Key)
    Next Key

End Function

上述函数使用后期绑定,因此您不需要对脚本运行时的引用。这使您可以轻松地将此功能放入任何 VBA 项目中,而不会遇到任何麻烦。 Early-binding 会给你带来性能提升和智能感知,所以尽可能使用它是有意义的。

这是一个示例过程,说明了上述函数的作用(请注意,示例需要引用 Microsoft Scripting Runtime)。如有任何问题,请在 cmets 中提问。

Sub Sample_DictionaryShallowCopy()
    Dim A As Dictionary, A_Nothing As Dictionary
    Set A_Nothing = DictionaryDeepCopy(A)
    Debug.Print A_Nothing Is Nothing
    'True

    Set A = New Dictionary

    Dim A0 As Dictionary
    Set A0 = DictionaryDeepCopy(A)

    A.Add "Texas", "Austin"
    A.Add "New York", "Albany"

    Dim B As Dictionary
    Set B = DictionaryShallowCopy(A)
    B.Add "Pennsylvania", "Harrisburg"

    Debug.Print A0.Count, A.Count, B.Count
    ' 0             2             3

    Dim C As New Dictionary
    C.Add A, "Dictionary A"
    C.Add B, "Dictionary B"
    Dim D As Dictionary
    Set D = DictionaryShallowCopy(C)
    'The Key type is maintained during the copy, even if the key is an object:
    Debug.Print TypeName(C.Keys(0)), TypeName(D.Keys(0))
    'Dictionary    Dictionary

    Dim E As New Dictionary
    E.Add "DictA", A

    Dim F As Dictionary
    Set F = DictionaryShallowCopy(E)
    F.Add "DictB", B

    F("DictA")("Texas") = "Houston"
    'This is a shallow copy, so the items that are objects are
    '    "copied" by reference, not by value:
    Debug.Print A("Texas"), E("DictA")("Texas"), F("DictA")("Texas")
    'Houston       Houston       Houston

    'If this were a DeepCopy, then the above line would have outputted:
    'Austin        Austin        Houston
End Sub

【讨论】:

  • 不错的收获。你是对的,这确实是一个浅拷贝。字典的通用深拷贝是不可能的,因为您无法知道如何深拷贝字典中的对象。
  • 这对我来说很有效,因为我的键实际上并不是 RubberDuck 回答中所要求的整数。不过,必须对深 v 浅拷贝做一些额外的阅读;你能简要解释一下我在使用这种方法时可能遇到的限制吗?
  • @jm158:我在答案中的示例过程中添加了一些额外的代码和 cmets,以显示深拷贝和浅拷贝之间的区别。主要限制是,如果您将对象存储在字典中,它们仍然是通过引用而不是值来“复制”的。因此,对一个字典中的对象的更改将更新复制字典中的对象。这是因为您根本没有真正复制字典中的对象……只是对对象的引用。
  • 如果你真的有动力可以创建一个深拷贝函数,但它不适用于通用字典对象。您需要创建一个自定义字典类,它只接受实现了 DeepCopy 方法的对象。您可以通过拥有一个带有空 Function DeepCopy() As iDeepCopy 函数的 iDeepCopy 类来做到这一点。然后,您添加到字典中的任何对象都必须在其类模块的声明部分中包含 Implements iDeepCopy。但是,到那时,您开始突破您在 VBA 中可以/应该做的事情的极限。
  • @mwolfe02 我不知道我是否同意您的评估,即它会突破 VBA 可以或应该做的事情的极限。自定义 dict 类对我来说听起来很合理。这取决于 OP 真正想在字典中存储什么。现在this is pushing the limits of what can/should be done in VBA.
【解决方案2】:

为此,您需要切换键和值,以便整数是键,字符串是值。类似的东西。

Sub testdic()
    Dim d
    Set d = CreateObject("Scripting.Dictionary")
    d.Add 1, "first"
    Dim s
    Set s = CreateObject("Scripting.Dictionary")

    Dim i as long
    For i = 0 to d.Items.Count -1
        s(i) = d.Items(i)
    Next i

    s.Add 2, "second"
End Sub

This question about iterating items in a dictionary may also be of interest.

【讨论】:

  • 无法遍历项目?知道为什么“设置”会在对象之间创建链接吗?谢谢
  • 这只是基本的对象引用。该变量不包含实际对象。它只是持有对象的引用
  • @jm158 我想说重要的部分是对CreateObject 的两个不同的调用——如果你想要一个对象的两个不同的实例,你需要创建两个不同的引用。否则你只是设置一个指向另一个的引用,两个句柄指向同一个对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-13
  • 2013-10-04
  • 2018-02-09
  • 1970-01-01
  • 2011-11-04
  • 1970-01-01
相关资源
最近更新 更多