当我更改一个集合列表中的值时,另一个列表是第一个列表的副本,也会更改

时间:2014-11-22 16:03:01

标签: vb.net collections

我正在vb 2010中写一个项目 我的问题在这里:

    Dim s1 As New List(Of blocks)
    Dim s As New blocks
    s.Type = blocks.Khane_Type.Block
    s1.Add(s)
    s = New blocks
    s.Type = blocks.Khane_Type.Hadaf
    s1.Add(s)
    Dim s2 As List(Of blocks) = New List(Of blocks)
    s2 = s1.GetRange(0, 2)

    s1(0).Type = blocks.Khane_Type.Player

    MsgBox(s2(0).Type.ToString)

当我更改s1列表中的值时,s2列表也会更改。为什么??????有什么问题?

2 个答案:

答案 0 :(得分:0)

msdn.microsoft.com/en-us/library/21k0e39c%28v=vs.110%29.aspx

s2的元素仍然指向相同的底层对象(它是浅层副本)。

即。 s2包含与s1

的元素0,1和2相同的块对象实例的引用

制作对象的完整副本取决于Block类的功能。您可能会发现http://msdn.microsoft.com/en-us/library/t63sy5hs.aspx基本概述了值类型和有用的引用类型之间的区别。

如果Block类只有值类型字段,那么成员克隆http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone%28v=vs.110%29.aspx就足够了(此链接也解释了浅拷贝和深拷贝之间的关键差异)。

如果它包含引用字段(例如对其他对象的引用),则应添加.Copy或.Clone方法。本质上,这样的方法将创建其类的新实例,将其值分配给新的类值字段(或首先执行成员克隆)并处理引用类型(如何取决于它们是什么)。

您应该开始一个新的问题来解释您的Block对象以及制作它的实例副本的最佳实践。

答案 1 :(得分:0)

s2是"浅拷贝"你的列表,这意味着复制指针而不是对象本身。如果你想复制"内容"你的对象(而不是指针),你应该做一个深拷贝。我准备了这个简单的工作示例,希望它有助于理解概念并修复代码。

    Dim a As List(Of String) = New List(Of String)
    a.Add("ciao")
    a.Add("hi")
    a.Add("hallo")

    'shallow copy sc
    Dim sc As List(Of String) = New List(Of String)
    sc = a 'sc will store just the pointer of a. So, if a changes, sc changes as well since it still points to the object a.

    'deep copy dc
    Dim dc As List(Of String) = New List(Of String)
    Using stream As New System.IO.MemoryStream()

        Dim formatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
        formatter.Serialize(stream, a)
        stream.Seek(0, IO.SeekOrigin.Begin)
        dc = formatter.Deserialize(stream) 'dc is storing the content of a in its own memory. It's a bit longer procedure because you need to create it a memory, but now even if a changes, dc will be the same.

    End Using

    a(1) = "goodbye"

    MsgBox("sc(1) changed to " & sc(1) & " while dc(1) is still " & dc(1))

因此,按照上面的示例,如果用以下代码替换s2 = s1.GetRange(0,2),您将看到s2不会与s1一起更改,您可以根据需要更改s1而不会影响s2:< / p>

Using stream As New System.IO.MemoryStream()

    Dim formatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
    formatter.Serialize(stream, s1)
    stream.Seek(0, IO.SeekOrigin.Begin)
    s2 = formatter.Deserialize(stream) 

End Using