2011-04-25 3 views
1

У меня проблема с использованием BinaryFormatter.Serialize.BinaryFormatter.Serialize with MemoryStream issue

У меня есть этот общий метод расширения для «клон» объект с помощью двоичной сериализации:

<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 

Я также класс называется «Режим», который имеет метод «Clone» следующим образом:

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

В моем графическом интерфейсе у меня есть функция, которая позволяет клонировать объект выбранного объекта. Пользователь вводит ряд новых имен режимов и обычных циклов с помощью этих новых имен, создавая клонов выбранного режима:

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

Вот моя проблема. Во время множественных вызовов CloneViaSerialization длина MemoryString (как показано в инструкции Debug.WriteLine) почти вдвое больше, чем был предыдущий вызов. Например, делая пять клонов, выход отладки:

МС ДЛИНА = 106882 МС ДЛИНА = 188048 МС ДЛИНА = 350482 МС ДЛИНА = 675350 МС ДЛИНА = 1325086

Это убийство. Что-нибудь еще, что около 7 или 8 клонов приносит приложение к остановке. Почему это произойдет? Блок USING должен гарантировать, что MemoryString будет удален, не так ли? Не следует ли каждый раз создавать новую MemoryString? Я думаю, так как тот же оригинальный объект Mode является источником сериализации, длина MemoryString будет одинаковой. Есть идеи? Что мне здесь не хватает?

Заранее благодарен!

+0

Каковы другие свойства класса Mode? Есть ли свойство, которое позволяет режимам ссылаться на другие режимы? – rsbarro

+0

Нет. Другими свойствами являются все String, Int16 или List (из Int16). Несмотря на это, я бы подумал, что, поскольку это один и тот же объект Mode, клонированный несколько раз, размер MemoryString всегда должен быть одним и тем же, не так ли? – Steve

+0

Да, это странно. Есть ли причина, по которой вы клонируете, используя сериализацию, вместо того, чтобы просто использовать 'base.MemberwiseClone()'? – rsbarro

ответ

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.

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

+0

Концепция глубокого клона будет работать для меня. К сожалению, для пользовательских методов клонирования требуется несколько десятков классов (которые я надеялся клонировать в общем случае с помощью CloneViaSerialization), но хорошо. Рабочая функциональность важнее того, что простое обслуживание кода ... Спасибо за вашу помощь. – Steve

+0

OK, круто. Рад, что смог помочь. – rsbarro