2016-05-13 65 views
5

我已經在C#中使用拷貝構造函數實現了一個深層克隆方法。爲了驗證它的工作原理,我通過比較序列化對象和它的克隆的結果來測試它。序列化是按照通用對象T完成的。我也嘗試過使用具體對象來獲得相同的結果。序列化修改C#中原始對象的內容#

我有序列化對象轉換成字節數組

private byte[] ObjectToBytes(T obj) 
{ 
    BinaryFormatter formatter = new BinaryFormatter(); 
    using (MemoryStream stream = new MemoryStream()) 
    { 
     formatter.Serialize(stream, obj); 
     stream.Seek(0, SeekOrigin.Begin); 
     return stream.ToArray(); 
    } 
} 

下面的代碼正常工作的方法。

T original = this.GetNewThing(); 
T clone = original.DeepClone(); 

// serialize after cloning 
byte[] originalBytes = ObjectToBytes(original); 
byte[] cloneBytes = ObjectToBytes(clone); 

bool equal = true; 
for (int i = 0; i < originalBytes.Length; i++) 
{ 
    if(originalBytes[i] != cloneBytes[i] 
    { 
     equal = false; 
     break; 
    } 
} 
equal == true; // True! 

但是,當我切換對象序列化的順序時,字節數組不再相等。

// serialize before cloning 
T original = this.GetNewThing(); 
byte[] originalBytes = ObjectToBytes(original); 

T clone = original.DeepClone(); 
byte[] cloneBytes = ObjectToBytes(clone); 

bool equal = true; 
for (int i = 0; i < originalBytes.Length; i++) 
{ 
    if(originalBytes[i] != cloneBytes[i] 
    { 
     equal = false; 
     break; 
    } 
} 
equal == true; // False! 

爲什麼序列化的順序會影響它呢?它與BinaryFormatter或MemoryStream對象有什麼關係?

編輯:

下面是深clone方法看起來像

public MyClass DeepClone() 
{ 
    return new MyClass(this); 
} 

和構造它使用看起來像這樣

protected MyClass(MyClass myClass) 
{ 
    if (myClass == null) 
     throw new ArguementNullException("myclass"); 

    this.number = myClass.Number; 
    this.number2 = myClass.Number2; 
    this.number3 = myClass.Number3; 
} 

目的是絕不復雜。所有被複制的值都是值類型,所以沒有需要擔心的引用類型。

+6

請發佈DeepClone方法..有可能是這個問題 –

+0

可能與對象的複雜性有關 - 檢查了這一點:http://stackoverflow.com/questions/5017274/binaryformatter-and-deserialization-complex -objects – Clay

+0

想想我們也可能需要查看完整的「MyClass」。此外,它沒有狀態,爲什麼ObjectToBytes是一個私有實例方法,而不是靜態的?我認爲這可能會有幫助,如果你可以格式化一個完整的示例代碼,可以剪切/粘貼到LinqPad。 –

回答

4

DeepClone,什麼也依次調用,似乎正在改變你的源對象的狀態。

+0

DeepClone通過訪問一個屬性來更改源對象直到第一次訪問時才設置。當我在創建字節數組之前克隆時,這很好,因爲這兩個屬性都在深度克隆期間被初始化。在克隆之前創建字節數組並不會導致此屬性被初始化,並且序列化不會獲取已初始化的值(該屬性是一個值類型,所以它會選擇默認值)。 – Danny

1

您必須修改ObjectToBytes方法如下:

private byte[] ObjectToBytes(Object obj) 
    { 
     if(obj == null) 
      return null; 

     BinaryFormatter bf = new BinaryFormatter(); 
     using(MemoryStream ms = new MemoryStream()) { 
      bf.Serialize(ms, obj); 

      return ms.ToArray(); 
     } 
    } 

希望它可以幫助

+0

你能解釋一下你認爲這有幫助嗎? – adv12

+0

@ adv12,因爲在.ToArray之前更改流位置是一種不好的做法。這是一個嘗試,但我希望看到DeepClone的實施。 – RobertoB

+0

我在我的代碼中刪除了對'Seek'的不必要的調用。它沒有解決這個問題。當我移除它時也沒有引起任何問題,所以我將把它排除在外。 – Danny