在C#中如何复制一个对象

51

假设我有一个类:

class obj
{
  int a;
  int b;
}

然后我有这段代码:

obj myobj = new obj(){ a=1, b=2}
obj myobj2 = myobj;
现在上面的代码引用了第一个对象。我的需求是让myobj2引用一个myobj的副本,而不会反映在原始对象中的更改。我已经在SO上搜索过,并且迄今为止的解决方案似乎很复杂。是否有更简单的方法来实现这一点。我正在使用.NET 4.5

写一个复制构造函数怎么样? - geniaz1
2个回答

100
您的对象中的属性是值类型,可以在这种情况下使用浅拷贝:
obj myobj2 = (obj)myobj.MemberwiseClone();

但在其他情况下,比如任何成员是引用类型,那么你需要进行深拷贝。你可以使用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);
    }
}

设置StreamingContext的目的是:我们可以通过实现ISerializable接口或使用内置属性(如OnDeserializedOnDeserializingOnSerializingOnSerialized)来引入特殊的序列化和反序列化逻辑到我们的代码中。在所有情况下,StreamingContext将作为参数传递给方法(对于ISerializable接口的特殊构造函数也是如此)。通过将ContextState设置为Clone,我们只是向该方法“提示”序列化的目的。 附加信息:(您还可以从MSDN阅读本文) 浅复制是创建一个新对象,然后将当前对象的非静态字段复制到新对象中。如果字段是值类型,则执行字段的位拷贝;对于引用类型,复制引用但不复制所引用的对象;因此原始对象及其克隆体引用同一对象。 深复制是创建一个新对象,然后将当前对象的非静态字段复制到新对象中。如果字段是值类型,则执行字段的位拷贝。如果字段是引用类型,则执行所引用对象的新副本。

4
这个答案已经被提出了。在特定条件下它是可行的,但正如先前所述,它会在中等信任环境下失败或者如果某些属性不可序列化(例如字典)时也会失败。此外,它需要大量开销,在适当的条件下会导致明显的减速。使用时请谨慎——它可能会使你的代码难以维护。附加信息值得一点赞。 - JDB
2
谢谢!我必须指出,复制对象及其所有子对象都应标记为[Serializable] - NoWar

9
您可以使用 MemberwiseClone 方法。
obj myobj2 = (obj)myobj.MemberwiseClone();

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

如果您拥有源代码,还可以实现ICloneable


4
这适用于简单的对象。对于更复杂的类型,您可能需要实现自己的逐字段复制,特别是如果任何成员本身就是引用类型。 - Joel Coehoorn
3
为什么我不能在我的对象上调用.MemberwiseClone()方法?所有对象都继承自Object,应该都有这个功能吧?但它显示不是一个方法。它只适用于某些类型的对象吗? - NickG
2
@NickG 该方法在Object上定义,因此存在于任何类/结构中。但是,该方法是“protected”。因此,如果您所在的类或派生自expression类型,则可以调用expression.MemberwiseClone()。例如,在上面的答案中,myobj是表达式,它具有类型obj,因此只能在类obj内部或派生自obj的类内部调用MemberwiseClone - Jeppe Stig Nielsen
4
应该翻译为:如果你在类obj内部或者在从obj派生出的类内部。 - Jeppe Stig Nielsen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接