VBA集合类:未授权的数据覆盖

时间:2017-11-08 13:19:32

标签: vba class dictionary collections

我有一个Collection Class(或者更确切地说是一个字典类),用于存储可变数量的edge对象。当我尝试通过循环填充包含所有信息的Dictionary时,数据会被不断覆盖,我似乎无法弄清楚原因。相关课程的代码如下:

null

生成Edges对象的Sub如下:

Option Explicit

Private pEdges As New Scripting.Dictionary

Property Get Count() As Long
    Count = pEdges.Count
End Property

Property Get EdgeByName(ByVal iName As Variant) As cEdge
    Set EdgeByName = pEdges(iName)
End Property

'Would it be better to pass all of the data to this add sub, and create 
'the class objects here, rather than creating a temporary class object and 
'just passing it along?
Sub Add(ByVal iEdge As cEdge)
    Dim Edge As New cEdge
    Set Edge = iEdge
    pEdges.Add Edge.Name, Edge
End Sub

Sub Remove(ByVal iName As Variant)
    pEdges.Remove (iName)
End Sub

Sub RemoveAll()
    pEdges.RemoveAll
End Sub

Sub PrintNames()
    Dim Key As Variant
    For Each Key In pEdges
        Debug.Print Key & " - " & pEdges(Key).Name & vbCrLf;
    Next
    Debug.Print vbdrlf;
End Sub

dEdges.PrintNames子句的输出是我用来调试它的(因为Watches窗口没有显示字典的项目数据)。 当循环继续时,它会打印键对应的边缘对象的Key和Name Value。如果工作正常,这两个字符串应该是相同的。虽然如此,每次我向字典添加一个新的边缘对象时,它都会覆盖所有先前输入的键的对象。我怀疑这与我创建一个TempEdge变量传递给Collection Class的事实有关,但我不确定。

输出示例:

Sub CalculateEdges(cCavities() As cCavity, dEdges As cEdges)
    Dim i As Integer

    For i = 1 To UBound(cCavities)
        Dim TempEdge As cEdge
        Set TempEdge = New cEdge
        Dim AdjSize As Integer
        AdjSize = cCavities(i).AdjacencySize
        If AdjSize> MaxEdges Then MaxEdges = AdjSize
        Dim j As Integer
        For j = 1 To AdjSize
            With TempEdge
                'Edge Names are a combination of two node names
                .Name = cCavities(i).Name & cCavities(i).Adjacency(j)
                'Sets the start node (Object) for the edge
                .SetNode cCavities(i), 0
                'Sets the end node (Object) for the edge
                .SetNode BackGround.NodeByName(cCavities, cCavities(i).Adjacency(j)), 1
                'Used later in program
                .Value = 0
            End With
            dEdges.Add TempEdge
            dEdges.PrintNames
        Next j
    Next i
End Sub

这只是一个被测试的单个数据点,但让我向您保证,cEdge对象中的所有变量都会被覆盖,而不仅仅是名称字符串。这是最容易检查的,因为它只是一个字符串。

作为旁注,如果有办法看到存储在字典中的对象,类似于"手表"窗口,我非常想知道怎么做。我在这一点上甚至使用临时边缘的全部原因是我可以跟踪循环中任何给定点进入字典的数据。

第二方注意,如果我可以使这个工作,我很可能将cCavities数组切换到类似的集合类。它目前不是一个,因为我似乎无法使它们正常工作。

2 个答案:

答案 0 :(得分:1)

将集合“ TempEdge = New cEdge”移入循环将在每个循环中创建一个新实例和一个新指针位置,同时保持对先前指针的集合引用。

/**
 * @param {import("./mymodule").customProps } customProps
 */
export function setGlobalStyle(obj, customProps) {
    customProps. // has full auto-completion 

结束子

答案 1 :(得分:0)

我继续将所有数据传递给add例程的想法,似乎已经解决了这个问题。我仍然想知道为什么我使用的方法不起作用,所以请随时评论或回答。

解决方案是更改cEdges.Add Sub以接受曾经传递给临时边缘变量的所有单个参数:

Sub Add(ByVal iName As String, iNode1 As cCavity, iNode2 As cCavity, iValue As Integer)
    Dim Edge As New cEdge
    With Edge
        .Name = iName
        .SetNode iNode1, 0
        .SetNode iNode2, 1
        .Value = iValue
    End With
    pEdges.Add Edge.Name, Edge
End Sub

这会将填充循环更改为:

Sub CalculateEdges(cCavities() As cCavity, dEdges As cEdges)
    Dim i As Integer

    For i = 1 To UBound(cCavities)
        Dim AdjSize As Integer
        AdjSize = cCavities(i).AdjacencySize
        If AdjSize > MaxEdges Then MaxEdges = AdjSize
        Dim j As Integer
        For j = 1 To AdjSize
            dEdges.Add cCavities(i).Name & cCavities(i).Adjacency(j), cCavities(i), BackGround.NodeByName(cCavities, cCavities(i).Adjacency(j)), 0
            dEdges.PrintNames
        Next j
    Next i
End Sub

此代码,尤其是.Add行,可以清除。我很可能会这样做,但现在这很好。

编辑:经过进一步的研究和更多的反复试验,我发现了数据被覆盖的原因。 Set关键字只创建一个指向原始值的指针,有效地使我的上面的代码有一个对象,TempEdge变量,以及指向它的一大堆不同的头。这就是为什么当编辑Temp边缘时,所有后续头部都会改变。