How to make a copy of an object in c#
假设我有一个班级:
1 2 3 4 5
| class obj
{
int a;
int b;
} |
然后我有了这个代码:
1 2
| obj myobj = new obj (){ a =1, b =2}
obj myobj2 = myobj ; |
现在上面的代码引用了第一个对象。我想说的是,myobj2指的是myobj的一份副本,其更改没有反映在原件中。我已经搜索过了,到目前为止解决方案似乎很复杂。有更简单的方法吗?我正在使用.NET 4.5
对象中的属性是值类型,您可以在以下情况下使用浅副本:
1
| obj myobj2 = (obj)myobj.MemberwiseClone(); |
但在其他情况下,如任何成员都是引用类型,则需要进行深度复制。在BinaryFormatter类的帮助下,您可以使用Serialization和Deserialization技术获得对象的深度副本:
1 2 3 4 5 6 7 8 9 10 11
| 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 );
}
} |
设置StreamingContext的目的:我们可以通过实现ISerializable接口或使用诸如OnDeserialized、OnDeserializing、OnSerializing、OnSerialized等内置属性,为代码引入特殊的序列化和反序列化逻辑。在所有情况下,StreamingContext都将作为参数传递给方法(对于ISerializable接口,则传递给特殊的构造函数)。在将ContextState设置为Clone时,我们只是提示该方法序列化的目的。
其他信息:(您也可以从msdn阅读本文)
浅复制是创建一个新对象,然后将当前对象的非静态字段复制到新对象。如果字段是值类型,则执行字段的逐位复制;对于引用类型,则复制引用,但不复制引用的对象;因此原始对象及其克隆引用同一对象。
深度复制正在创建一个新对象,然后将当前对象的非静态字段复制到新对象。如果字段是值类型,则执行字段的逐位复制。如果字段是引用类型,将执行被引用对象的新副本。
- +我终于明白了它们之间的区别。
- 已经提出了这个答案。它在某些条件下工作,但如前所述,它将在中等信任环境中失败,或者某些属性不可序列化(如字典)。它还需要大量的开销,因此在适当的条件下会导致明显的减速。小心使用-这可能会使代码难以维护。+但是,如果需要更多信息,请访问1。
- @Cyborgx37非常好。谢谢你的解释。
- 谢谢您!我需要注意的是,压顶对象及其所有子对象都应标记为[Serializable]。
可以使用MemberWiseClone
1
| obj myobj2 = (obj)myobj.MemberwiseClone(); |
拷贝是一个浅拷贝,这意味着克隆中的引用属性指向的值与原始对象相同,但在您的情况下,这不应该是问题,因为obj中的属性是值类型。
如果您拥有源代码,还可以实现ICloneable
- 这适用于简单对象。对于更复杂的类型,您可能需要实现自己的逐字段复制,特别是如果任何成员本身就是引用类型。
- 为什么我不能对我的对象调用.memberWiseClone()?当然,所有的物体都是从物体继承来的,因此应该有这个功能吗?它说这不是一种方法。它是否只适用于某些类型的对象?
- @nickg方法在Object上定义,因此存在于任何类/结构中。但是,方法是protected。因此,如果您所在的类是或派生自expression的类型,则可以调用expression.MemberwiseClone()。例如,在上面的答案中,myobj是表达式,它的类型是obj,因此,如果您在obj类或从obj派生的类中,只能在它上面调用MemberwiseClone。
- 如果您在obj类中,或者在obj派生的类中,那么应该是:…。