1

我在使用 BinaryFormatter.Serialize 时遇到问题。

我有这个通用的扩展方法来通过二进制序列化“克隆”一个对象:

<Extension()>
Public Function CloneViaSerialization(ByRef Obj as System.Object)
   Dim NewObj As System.Object
   Using MS As New System.IO.MemoryStream
      Dim Formatter as New BinaryFormatter
      Formatter.Serialize(MS, Obj)
      Debug.WriteLine("MS LENGTH = " & MS.Length)
      MS.Position = 0
      NewObj = Formatter.Deserialize(MS)
   End Using
   Return NewObj
End Function

我还有一个名为“Mode”的类,它有一个“Clone”方法,如下所示:

Friend Function Clone()
   Dim NewMode as Mode = Me.CloneViaSerialization
   Return NewMode
End Function

在我的 GUI 中,我有一个函数允许克隆选定的 Mode 对象。用户输入一系列新模式名称,并且例程通过这些新名称循环创建所选模式的克隆:

Private Sub MakeClones(ByRef ModeToClone as Mode, ByVal CloneNames as List(Of String))
   For Each CloneName as String in CloneNames
      Dim NewMode as Mode = ModeToClone.Clone
      NewMode.Name = CloneName
      ParentObject.Modes.Add(NewMode)
   Next
End Sub

所以基本上应该创建所选模式对象的一个​​或多个克隆,将 Name 属性设置为正确的值,并将新的模式对象添加到父对象。这涉及对 Mode.Clone 方法的 X 次调用以及对 CloneViaSerialization 扩展方法的 X 次调用。

这是我的问题。在多次调用 CloneViaSerialization 期间,MemoryString 长度(如 Debug.WriteLine 语句所示)几乎是上一次调用的两倍。例如,制作五个克隆,调试输出为:

毫秒长度 = 106882 毫秒长度 = 188048 毫秒长度 = 350482 毫秒长度 = 675350 毫秒长度 = 1325086

这是杀戮的表现。超过 7 或 8 个克隆会使应用程序停止运行。为什么会发生这种情况?USING 块应该确保 MemoryString 被处理掉,对吧?不应该每次都创建一个新的 MemoryString 吗?我认为由于相同的原始模式对象是序列化的源,因此 MemoryString 长度将是相同的。有任何想法吗?我在这里想念什么?

提前致谢!

4

1 回答 1

0

我不确定您为什么要CloneViaSerialization消耗大量内存,您发布的代码对我来说似乎没问题(尽管一种可能的解释可能是被克隆的数据很大)。另一种方法是仅ICloneable在您的Mode类上实现并设置您的Clone函数来对您的对象进行深层复制。

Public Class Mode 
    Implements ICloneable

    Private m_Prop1 As String
    Public Property Prop1() As String
        Get
            Return m_Prop1
        End Get
        Set
            m_Prop1 = Value
        End Set
    End Property

    Private m_Prop2 As Int16
    Public Property Prop2() As Int16
        Get
            Return m_Prop2
        End Get
        Set
            m_Prop2 = Value
        End Set
    End Property

    Private m_Prop3 As List(Of Int16)
    Public Property Prop3() As List(Of Int16)
        Get
            Return m_Prop3
        End Get
        Set
            m_Prop3 = Value
        End Set
    End Property

    Public Function Clone() As Object Implements ICloneable.Clone
        Dim objClone as Mode
        objClone = MemberwiseClone()
        If Not Me.Prop3 Is Nothing Then
            objClone.Prop3 = new List(Of Int16)
            objClone.Prop3.AddRange(Me.Prop3)
        End If
        Return objClone
    End Function

End Class

请注意,在Clone函数中,我们需要单独复制List(Of Int16). MemberwiseClone会将引用复制到它创建的新对象中,因此如果我们不创建新对象List(Of Int16)并手动复制其中的值,那么我们将在克隆中引用对原始列表的引用。

我还应该指出,有些人在实现ICloneable和让它做深拷贝时可能会遇到问题,因为MemberwiseClone只做浅拷贝。如果这让您感到困扰,那么您可以随时重命名CloneDeepClone删除该ICloneable界面。

希望有帮助。

于 2011-04-26T06:12:30.447 回答