【问题标题】:How to make a copy of an object in C# [duplicate]如何在 C# 中制作对象的副本 [重复]
【发布时间】:2013-05-17 18:44:53
【问题描述】:

假设我有一堂课:

class obj
{
  int a;
  int b;
}

然后我有这个代码:

obj myobj = new obj(){ a=1, b=2}
obj myobj2 = myobj;

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

【问题讨论】:

  • 写一个拷贝构造函数怎么样?

标签: c# .net clone


【解决方案1】:

对象中的属性是值类型,您可以在这种情况下使用浅拷贝:

obj myobj2 = (obj)myobj.MemberwiseClone();

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

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阅读这篇文章)

浅拷贝是创建一个新对象,然后将当前对象的非静态字段复制到新对象。如果字段是值类型,则对该字段进行逐位复制;对于引用类型,引用被复制但被引用的对象不是;因此原始对象和它的克隆引用同一个对象。

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

【讨论】:

  • +1 终于知道这两者有什么区别了。
  • 这个答案has already been proposed。它在某些条件下工作,但如前所述,它在中等信任环境中或某些属性不可序列化(例如字典)时会失败。它还需要大量开销,因此在适当的条件下会导致明显的减速。谨慎使用 - 它可能会使您的代码难以维护。不过,为其他信息 +1。
  • @Cyborgx37 非常好。谢谢你的解释。
  • 谢谢!我必须注意,应对对象及其所有子对象应标记为[Serializable]
【解决方案2】:

您可以使用MemberwiseClone

obj myobj2 = (obj)myobj.MemberwiseClone();

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

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

【讨论】:

  • 这适用于简单的对象。对于更复杂的类型,您可能需要实现自己的逐字段复制,尤其是如果任何成员本身就是引用类型。
  • 为什么我不能在我的对象上调用 .MemberwiseClone()?当然所有对象都继承自 Object 并因此应该具有此功能?它说这不是一种方法。它只适用于某些类型的对象吗?
  • @NickG 该方法在Object 上定义,因此存在于任何类/结构中。但是,方法是protected。因此,如果您所在的类是或派生自expression 的类型,则可以调用expression.MemberwiseClone()。例如在上面的答案中,myobj 是表达式,它的类型为obj,所以如果你在obj 类内或从obj 派生的类内,你只能在其上调用MemberwiseClone .
  • 应该是:...如果您在 obj 类中或在 obj 派生的类中。
猜你喜欢
  • 2018-08-08
  • 1970-01-01
  • 2011-09-28
  • 1970-01-01
  • 1970-01-01
  • 2015-12-28
相关资源
最近更新 更多