BinaryFormatter.Serialize与MemoryStream问题

时间:2011-04-25 20:19:20

标签: vb.net serialization binaryformatter

我在使用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

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

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

  

MS LENGTH = 106882   MS LENGTH = 188048   MS LENGTH = 350482   MS LENGTH = 675350   MS LENGTH = 1325086

这是杀戮表现。任何超过7或8个克隆的东西都会让应用程序停止运行。为什么会这样? USING块应该确保处理MemoryString,对吧?不应该每次都创建一个新的MemoryString吗?我认为,因为相同的原始Mode对象是序列化的源,MemoryString长度将是相同的。有任何想法吗?我在这里缺少什么?

提前致谢!

1 个答案:

答案 0 :(得分: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只执行浅拷贝。如果这让您感到困扰,那么您可以随时将Clone重命名为DeepClone并删除ICloneable界面。

希望有所帮助。