【问题标题】:VB.Net Copy a list to store original values to be used laterVB.Net 复制一个列表以存储原始值以供以后使用
【发布时间】:2012-05-31 11:34:00
【问题描述】:

我有一个 WPF 表单,它采用具有位置和大小的对象列表并将它们绘制在画布上。我目前正在尝试实现一个撤消按钮,该按钮将丢弃对对象位置所做的所有更改,并恢复为加载表单时检索到的原始集合。

就目前而言,我在加载表单时访问数据库并获取所有需要显示的对象,然后将返回的列表分配给两个单独的集合。出现的问题是这两个集合实际上是指向原始集合的指针,并且每当更改一个集合时,更改都会反映在第二个集合中。

是否可以复制一个对象列表,以便对一个集合所做的更改不会影响第二个集合?

到目前为止,我已经尝试简单地使用赋值运算符,将源集合传递给函数 byval 并滚动列表的每个元素,手动将其添加到第二个集合中,并使用 linq 从原始列表并将结果推送到单独的临时列表,并将第二个集合分配给临时列表。

我觉得我把问题复杂化了,但我在谷歌搜索时遇到的几乎所有地方都说这种行为是设计使然,我理解这一点,但似乎这是一个相当普遍的想法。

【问题讨论】:

    标签: vb.net list collections


    【解决方案1】:

    使用此代码简单地将 listA 的所有项目分配给 listB

    For Each elm In ListA
       ListB.Add(elm) 
    Next
    

    【讨论】:

    • 从我的测试中我看到ListB 将包含对ListA 中项目的引用,因此对ListA 的任何更改都会反映在ListB 中。 Casey Wilkins 的深层副本为我解决了这个问题。
    【解决方案2】:

    这是我之前用来制作对象的“深度”副本的函数:

    Public Function DeepCopy(ByVal ObjectToCopy As Object) As Object
    
        Using mem as New MemoryStream
    
            Dim bf As New BinaryFormatter
            bf.Serialize(mem, ObjectToCopy)
    
            mem.Seek(0, SeekOrigin.Begin)
    
            Return bf.Deserialize(mem)
    
        End Using
    
    End Function
    

    与其他一些答案相比,这是一种低级方法,但允许您深度复制任何对象。我已经在与您类似的情况下成功使用了它,我需要一个数组的深层副本。

    【讨论】:

    • 在尝试实现此功能时,我注意到要使其尽可能通用,在您使用此功能时,我制作的所有自定义类都必须标记为serializable你有没有看到任何理由标记一个类 serializable 是不明智的?
    • 我不记得在自定义类上使用过它,所以我无法具体评论。但是,如果该类被标记为可序列化,我认为您不会遇到任何问题。
    • 在我所有受影响的类定义中添加<Serializable()>后,这个函数就像一个魅力,比我发现做大致相同工作的第三方控件快得多。
    【解决方案3】:

    您必须创建一个新列表并将 list1 中的项目的副本添加到其中。您可以使用对象初始化来做到这一点,例如

    Dim list2 = (From item in list1
                 Select New ItemType With {.Property1 = item.Property1, .Property2 = item.Property2}.ToList()
    

    另一种方法是将 Copy 构造函数添加到 ItemType

    Public Sub New(item as ItemType)
        Me.Property1 = item.Property1
        Me.Property2 = item.Property2
    End Sub
    

    您的列表副本可以简化为

    Dim list2 = (From item in list1
                 Select New ItemType(item)}.ToList()
    

    请注意,如果您的 ItemType 的任何属性是引用,您还需要制作这些对象的副本。 (这被称为Deep Copy

    【讨论】:

    • 我尝试过这样的事情,但我要复制的对象相当大,并且有额外的对象作为数据成员,所以从速度的角度来看它很快就会适得其反(递归函数调用和 100+起始对象的实例之类的东西)。另外,感谢您提供的链接,我熟悉它所讨论的原则,但从未听说过它们的名称,并且能够使用正确的术语来描述事物总是很好的。
    【解决方案4】:

    还有另一个答案已被删除,据说使用var copy = list.ToList(); 来获取列表的副本。这将适用于以下警告:两个列表仍将引用相同的对象,因此对这些对象的任何更改都将反映在两个列表中。只要您只更改列表中对象的顺序,此解决方案就完全可行。

    【讨论】:

    • 主要问题是某些值正在改变(在这种情况下是位置),所以这种方法没有奏效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多