2011-04-25 4 views
1

BinaryFormatter.Serialize를 사용하는 데 문제가 있습니다. MemoryStream 문제가있는 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 

나는 또한 클래스는 방법 "복제"다음과 같이있다 "모드"라고했다 :

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

GUI 내에서 선택한 모드 개체를 복제 할 수있는 기능이 있습니다. 사용자가 선택한 모드의 클론 생성하는 새 이름을 통해 새 모드 이름과 일상 사이클의 일련의 입력 : 그래서 기본적으로 선택된 모드 객체의 하나 또는 그 이상의 클론한다고

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 객체를 부모에 추가합니다. 여기에는 Mode.Clone 메서드에 대한 X 번 호출과 CloneViaSerialization 확장 메서드에 대한 X 번 호출이 포함됩니다.

여기에 문제가 있습니다. CloneViaSerialization을 여러 번 호출하는 동안 MemoryString 길이 (Debug.WriteLine 문에 표시됨)는 이전 호출과 거의 같습니다. 예를 들어, 다섯 개의 클론을 디버그 출력된다 :

MS 길이 = 106,882 MS 길이 = 188,048 MS 길이 = 350,482 MS 길이 = 675,350 MS 길이 이것은 1,325,086

이다 = 살해 성과. 약 7 ~ 8 개의 클론이 앱을 중단시킵니다. 왜 이런 일이 일어 났을까요? USING 블록은 MemoryString이 삭제되었는지 확인해야합니다. 맞습니까? 매번 새로운 MemoryString을 만들어야하지 않습니까? 동일한 원본 Mode 객체가 직렬화의 소스이기 때문에 MemoryString 길이가 같을 것이라고 생각합니다. 어떤 아이디어? 내가 여기서 무엇을 놓치고 있니?

미리 감사드립니다.

+0

Mode 클래스의 다른 속성은 무엇입니까? 모드가 다른 모드를 참조 할 수있게 해주는 속성이 있습니까? – rsbarro

+0

다른 속성은 모두 String, Int16 또는 Int16의 List입니다. 그럼에도 불구하고 여러 번 복제 된 동일한 Mode 객체이므로 MemoryString의 크기는 항상 같아야한다고 생각합니까? – Steve

+0

네, 그건 이상합니다. 'base.MemberwiseClone()'을 사용하는 대신에 직렬화를 사용하여 복제하는 이유가 있습니까? – rsbarro

답변

0

내가 왜 CloneViaSerialization이 많은 양의 메모리를 소비하는지 잘 모르겠다. 게시 한 코드는 나에게 잘 보이지만 (한 가지 가능한 설명은 복제 된 데이터가 클 수 있음). 다른 방법은 ICloneableMode 클래스에 구현하고 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 인터페이스를 제거 할 수 있습니다.

희망이 있습니다.

+0

깊은 복제 개념이 나를 위해 작동 할 것입니다. 불행히도 CloneViaSerialization을 사용하여 일반적으로 복제하기를 원했던 몇 가지 클래스의 사용자 정의 Clone 메서드가 필요합니다. 코드 유지 관리가 쉬워 진 작업 기능이 더 중요합니다 ... 도움을 주셔서 감사합니다. – Steve

+0

좋습니다. 다행히 도울 수있어. – rsbarro

관련 문제