BinaryFormatter.Serialize 与 MemoryStream 问题

发布于 2024-11-03 17:14:28 字数 1604 浏览 3 评论 0原文

我在使用 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”的类,它有一个“克隆”方法,如下所示:

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 语句中显示)几乎是前一次调用的两倍。例如,制作五个克隆,调试输出为:

MS 长度 = 106882 MS 长度 = 188048 MS 长度 = 350482 MS 长度 = 675350 MS 长度 = 1325086

这是令人窒息的性能。超过 7 或 8 个克隆就会导致应用程序停止运行。为什么会出现这种情况呢? USING 块应该确保 MemoryString 被释放,对吧?不应该每次都创建一个新的MemoryString吗?我认为由于相同的原始 Mode 对象是序列化的源,因此 MemoryString 长度将是相同的。有什么想法吗?我在这里缺少什么?

提前致谢!

I am having an issue using BinaryFormatter.Serialize.

I have this generic extension method to "clone" an object via binary serialization:

<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

I also have a class called "Mode" which has a method "Clone" as follows:

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

Within my GUI, I have a function that allows a selected Mode object to be cloned. The user enters a series of new mode names and the routine cycles through those new names creating clones of the selected 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

So basically one or more clones of the selected Mode object ought to be created, the Name property set to the correct value, and the new Mode objects added to the parent. This involves X number of calls to the Mode.Clone method and in-turn X calls to the CloneViaSerialization extension method.

Here's my issue. During multiple calls of CloneViaSerialization, the MemoryString length (as displayed at the Debug.WriteLine statement) is almost double what is was the previous call. For example, making five clones, the debug output is:

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

This is killing performance. Anything more that about 7 or 8 clones brings the app to a halt. Why would this happen? The USING block ought to ensure the MemoryString is disposed of, right? Shouldn't a new MemoryString be created each time? I would think since the same original Mode object is the source for the serialization, the MemoryString length would be the same. Any ideas? What am I missing here?

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

静谧幽蓝 2024-11-10 17:14:28

我不确定为什么您的 CloneViaSerialization 消耗大量内存,您发布的代码对我来说似乎没问题(尽管一种可能的解释可能是被克隆的数据很大)。另一种方法是仅在 Mode 类上实现 ICloneable 并设置 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 接口。

希望有帮助。

I'm not sure why your CloneViaSerialization is consuming large amounts of memory, the code you posted seems ok to me (although one possible explanation could just be that the data being cloned is large). An alternative approach is to just implement ICloneable on your Mode class and set up your Clone function to do a deep copy of your object.

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

Please be aware that in the Clone function, we need to do a separate copy of the List(Of Int16). MemberwiseClone will copy references into the new object it creates, so if we don't create a new List(Of Int16) and manually copy the values in then we'll wind up with a reference to the original list in the clone.

I also should point out that some people may have a problem implementing ICloneable and having it do a deep copy, since MemberwiseClone only does shallow copies. If that bothers you then you can always rename Clone to DeepClone and remove the ICloneable interface.

Hope that helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文