如何在c#中制作对象的副本

Win*_*der 36 .net c# clone

假设我有一节课:

class obj
{
  int a;
  int b;
}
Run Code Online (Sandbox Code Playgroud)

然后我有这个代码:

obj myobj = new obj(){ a=1, b=2}
obj myobj2 = myobj;
Run Code Online (Sandbox Code Playgroud)

现在上面的代码引用了第一个obj.我想要的是myobj2指副本中myobj没有反映在原文中的副本.我搜索了SO,到目前为止解决方案似乎很复杂.有没有更简单的方法来做到这一点.我正在使用.net 4.5

Far*_*yev 84

对象中的属性是值类型,您可以在这样的sutuation中使用浅拷贝:

obj myobj2 = (obj)myobj.MemberwiseClone();
Run Code Online (Sandbox Code Playgroud)

但在其他情况下,如果任何成员是引用类型,则需要Deep Copy.您可以在类的帮助下使用SerializationDeserialization技术获得对象的深层副本BinaryFormatter:

public static T DeepCopy<T>(T other)
{
    using (MemoryStream ms = new MemoryStream())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Context = new StreamingContext(StreamingContextStates.Clone);
        formatter.Serialize(ms, other);
        ms.Position = 0;
        return (T)formatter.Deserialize(ms);
    }
}
Run Code Online (Sandbox Code Playgroud)

设置的目的StreamingContext:我们可以采取特殊的序列化和反序列化逻辑,我们的代码与一个实现帮助ISerializable界面或使用内置的属性,如OnDeserialized,OnDeserializing,OnSerializing,OnSerialized.在所有情况下,StreamingContext都将作为参数传递给方法(如果是ISerializable接口,则传递给特殊构造函数).设置ContextStateClone,我们只是提示有关序列化目的的方法.

附加信息:(您也可以从MSDN阅读本文)

浅复制正在创建一个新对象,然后将当前对象的非静态字段复制到新对象.如果字段是值类型,则执行字段的逐位复制; 对于引用类型,引用被复制但引用的对象不是; 因此原始对象及其克隆引用相同的对象.

深层复制正在创建一个新对象,然后将当前对象的非静态字段复制到新对象.如果字段是值类型,则执行字段的逐位复制.如果字段是引用类型,则执行引用对象的新副本.

  • 这个答案[已经提出](http://stackoverflow.com/a/78612/211627).它在某些条件下工作,但如前所述,它将在中等信任环境中失败,或者某些属性不可序列化(如字典).它还需要很多开销,因此在适当的条件下会导致明显的减速.请谨慎使用 - 这可能会使您的代码难以维护.但是,附加信息为+1. (4认同)
  • +1终于得到了它们之间的区别. (3认同)
  • 谢谢!我必须注意,应对对象及其所有子对象应该标记为`[Serializable]`. (2认同)

vc *_* 74 7

您可以使用MemberwiseClone

obj myobj2 = (obj)myobj.MemberwiseClone();
Run Code Online (Sandbox Code Playgroud)

副本是浅拷贝,这意味着克隆中的引用属性指向与原始对象相同的值,但这在您的情况下应该不是问题,因为 中的属性obj是值类型。

如果你拥有源代码,你也可以实现ICloneable

  • 这适用于简单的对象。对于更复杂的类型,您可能需要实现自己的逐字段复制,特别是如果任何成员本身是引用类型。 (4认同)
  • 为什么我不能在我的对象上调用 .MemberwiseClone() ?肯定所有的对象都继承自 Object,因此应该有这个功能吗?它说这不是一种方法。它仅适用于某些类型的对象吗? (3认同)
  • 那应该是:_...如果你在类 `obj` 内或在派生 `obj` 的类内。_ (3认同)
  • @NickG 该方法定义在`Object` 上,因此存在于任何类/结构中。但是,该方法是“受保护的”。因此,如果您所在的类是或派生自“表达式”的类型,则您可以调用“表达式.MemberwiseClone()”。例如,在上面的答案中,`myobj` 是表达式,并且它的类型为 `obj`,所以如果你在类 `obj` 或派生自 `obj` 的类中,你只能在它上面调用 `MemberwiseClone` . (2认同)