BinaryFormatter.Serialize с проблемой MemoryStream - PullRequest
1 голос
/ 26 апреля 2011

У меня проблема с использованием 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 добавить в родительский объект. Это включает в себя количество вызовов X в метод Mode.Clone и, в свою очередь, вызов X в метод расширения CloneViaSerialization.

Вот моя проблема. Во время нескольких вызовов 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 голосов
/ 26 апреля 2011

Я не уверен, почему ваш 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.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...