2016-05-13 66 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