在 C# 中创建对象的副本 [重复]
Posted
技术标签:
【中文标题】在 C# 中创建对象的副本 [重复]【英文标题】:Creating a copy of an object in C# [duplicate] 【发布时间】:2011-09-28 00:13:06 【问题描述】:请看下面的代码(摘自一本 C# 书籍):
public class MyClass
public int val;
public struct myStruct
public int val;
public class Program
private static void Main(string[] args)
MyClass objectA = new MyClass();
MyClass objectB = objectA;
objectA.val = 10;
objectB.val = 20;
myStruct structA = new myStruct();
myStruct structB = structA;
structA.val = 30;
structB.val = 40;
Console.WriteLine("objectA.val = 0", objectA.val);
Console.WriteLine("objectB.val = 0", objectB.val);
Console.WriteLine("structA.val = 0", structA.val);
Console.WriteLine("structB.val = 0", structB.val);
Console.ReadKey();
我知道它会产生以下输出:
objectA.val = 20
objectB.val = 20
structA.val = 30
structB.val = 40
输出的最后两行我没有问题,但前两行告诉我objectA
和objectB
指向同一个内存块(因为在C# 中,对象是引用类型)。
问题是如何使objectB
成为objectA
的副本,以便它指向内存中的不同区域。我知道尝试分配他们的成员可能不起作用,因为这些成员也可能是参考。那么我该如何让objectB
成为与objectA
完全不同的实体呢?
【问题讨论】:
这可能会有所帮助:***.com/questions/129389/… 字符串 json = Newtonsoft.Json.JsonConvert.SerializeObject(myobject); myObjType rCopy = Newtonsoft.Json.JsonConvert.DeserializeObject没有内置方法。您可以让 MyClass 实现 IClonable
接口(但它已被弃用)或者只是编写您自己的 Copy/Clone 方法。无论哪种情况,您都必须编写一些代码。
对于大型对象,您可以考虑序列化 + 反序列化(通过 MemoryStream),只是为了重用现有代码。
无论采用何种方法,请仔细考虑“副本”的确切含义。它应该走多深,是否有要排除的 Id 字段等。
【讨论】:
很抱歉,我知道这是一篇很老的帖子,但您能否提供一个指向已弃用ICloneable
的文档的链接?我查看了 .net 4.5 的文档,ICloneable
没有说任何关于被弃用的信息。如果是的话,我想用别的东西。
没关系,我找到了。在.NET documentation 中,他们“建议不要在公共 API 中实现 ICloneable”。所以它没有被弃用,只是不推荐使用。
@LeeTaylor Deprecated 表示“表示不赞成”,在软件的上下文中,deprecated 表示完全反对使用。您不能拥有一个在公共而不是私有时被弃用的 API。已弃用的 API 已弃用,除非绝对必要,否则根本不应使用。 Microsoft 并没有说你绝对不应该使用它,因为它已被弃用(通常提供替代方案),它只是说避免在公共 API 中使用它。
@LeeTaylor Wikipedia 说“弃用是一种应用于计算机软件功能、特征或实践的属性,表明应该避免使用它(通常是因为它被取代了)”;避免就像完全避免,而不是基于可访问性而避免。
@LeeTaylor 最后一点,Microsoft 将Obsolete 属性添加到他们认为已弃用的类、结构、枚举、委托、方法、构造函数、属性、字段、事件和接口,这会导致编译器发出CS0618 警告,表明它确实已被弃用。 ICloneable
没有应用 Obsolete
属性。【参考方案2】:
已经有一个关于这个的问题,你也许可以阅读它
Deep cloning objects
没有 Clone() 方法,因为它存在于 Java 中,但你可以在你的类中包含一个复制构造函数,这是另一种好方法。
class A
private int attr
public int Attr
get return attr;
set attr = value
public A()
public A(A p)
this.attr = p.Attr;
这是一个示例,在构建新对象时复制成员“Attr”。
【讨论】:
【参考方案3】:你可以这样做:
class myClass : ICloneable
public String test;
public object Clone()
return this.MemberwiseClone();
那你就可以了
myClass a = new myClass();
myClass b = (myClass)a.Clone();
注意MemberwiseClone()
创建当前 System.Object 的浅表副本。
【讨论】:
-1 未提及浅/深克隆及其影响。如果没有这些信息,MemberwiseClone()
会很棘手。
-1 没有提到 ICloneable 已被弃用,不应使用。
@Tom :-1 对您的评论(如果可以的话)未提供有关您的声明的任何链接,因为 ICloneable 在official doc 中未标记为已过时)。您更多的是谈论最佳实践,而不是官方弃用状态。
... 但这会给出与用户原始问题相同的结果。直接来自文档:“如果字段是值类型,则执行字段的逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其克隆指的是同一个对象。” msdn.microsoft.com/en-us/library/…
嗯.. 它不被弃用,因此建议不要在公共 API 中使用,因为该 API 的消费者的实现不清楚,但对于内部使用或开源,我认为没关系。他们说的是“由于 Clone 的调用者不能依赖于执行可预测克隆操作的方法,我们建议不要在公共 API 中实现 ICloneable。”【参考方案4】:
最简单的方法是在 MyClass 类中编写一个复制构造函数。
类似这样的:
namespace Example
class MyClass
public int val;
public MyClass()
public MyClass(MyClass other)
val = other.val;
第二个构造函数简单地接受一个他自己类型的参数(你要复制的那个)并创建一个新的对象,分配了相同的值
class Program
static void Main(string[] args)
MyClass objectA = new MyClass();
MyClass objectB = new MyClass(objectA);
objectA.val = 10;
objectB.val = 20;
Console.WriteLine("objectA.val = 0", objectA.val);
Console.WriteLine("objectB.val = 0", objectB.val);
Console.ReadKey();
输出:
objectA.val = 10
objectB.val = 20
【讨论】:
这对学习很有好处。不是为了练习。 输出的第二行应该是objectB.val = 20
,无法编辑,因为编辑太小了
复制构造函数的问题是,如果添加/删除字段,还必须修改复制构造函数。这可能成为维护的噩梦。特别是对于具有许多字段的对象(50+,即 DataContract)。
我喜欢这个答案。 Clone 方法返回类对象,因此它是一种构造函数。那么,为什么叫它克隆而不使用类名呢?那么,何为“维修噩梦”?如果您需要维护大量字段,这是最好的选择。关于“弃用”:没有人强迫您从 IClonable 接口继承。您可以在没有接口的情况下实现 Clone() 方法。但毕竟我会在我的项目中实现复制构造函数。
我同意@Roland。使用 new 关键字,您肯定会创建一个具有不同地址的新对象。我看不出有什么问题。迷恋你可能更喜欢使用反射?以上是关于在 C# 中创建对象的副本 [重复]的主要内容,如果未能解决你的问题,请参考以下文章