C#中的深层复制

MSDN给出了这个深拷贝的例子( http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx )

public class Person { public int Age; public string Name; public IdInfo IdInfo; public Person ShallowCopy() { return (Person)this.MemberwiseClone(); } public Person DeepCopy() { Person other = (Person) this.MemberwiseClone(); other.IdInfo = new IdInfo(this.IdInfo.IdNumber); return other; } } 

但是,是否必须实例化一个新的Person对象,然后返回? 例如,此代码是否可接受/等于/低于上述执行深层复制的代码?

据我理解的是MemberwiseClone()方法,它只执行浅拷贝,即将复制对象的值/引用复制到新对象。 由于内存引用相等,这导致浅拷贝,即引用指向相同的对象。

 public class Person { public int Age; public string Name; public IdInfo IdInfo; public Person ShallowCopy() { return (Person)this.MemberwiseClone(); } public Person DeepCopy() { Person other = new Person(); // difference other.IdInfo = new IdInfo(this.IdInfo.IdNumber); return other; } } 

在您指定的示例中,Age和Name的值将为零/空。

这是因为您实例化Person对象,但从未设置这些字段的值。

来自Object.MemberwiseClone方法

MemberwiseClone方法通过创建新对象,然后将当前对象的非静态字段复制到新对象来创建浅表副本。 如果字段是值类型,则执行字段的逐位复制。 如果字段是引用类型,则复制引用但引用的对象不是; 因此,原始对象及其克隆引用相同的对象。

如您所见,使用MemberwiseClone方法,您的年龄/名称字段也将被复制/克隆。

或者,如果您能够将Serializable属性设置为所有涉及的类,则可以使用序列化。 出于通用深层副本的目的,我有这个object扩展方法:

 public static class ObjectExtensions { #region Methods public static T Copy(this T source) { var isNotSerializable = !typeof(T).IsSerializable; if (isNotSerializable) throw new ArgumentException("The type must be serializable.", "source"); var sourceIsNull = ReferenceEquals(source, null); if (sourceIsNull) return default(T); var formatter = new BinaryFormatter(); using (var stream = new MemoryStream()) { formatter.Serialize(stream, source); stream.Seek(0, SeekOrigin.Begin); return (T)formatter.Deserialize(stream); } } #endregion } 

这也应该复制您的IdInfo字段。

用法很简单:

 var copy = obj.Copy(); 

MemberwiseClone()创建要复制的类的新实例,并将标量字段复制到副本的相应成员中。 它提供了一个更好的深度复制起点,而不仅仅是一个普通的new ,因为你只需要“修复”需要深度复制的项目。

MemberwiseClone会创建一个新对象并复制所有非静态字段。 对于引用类型,这意味着复制引用。 所以是的,在成员明智克隆之后,新对象的字段指向与原始对象的字段相同的对象(对于引用类型)。 这就是MSDN中的示例创建IdInfo的新实例的IdInfo :也可以创建该对象的副本。

您的DeepCopy实现已被破坏,因为它不会复制所有字段,但如果这样,那么结果将与MemberwiseClone解决方案不同。

这个问题对您来说也许是一个有趣的读物: 在C#中创建一个深层复制

MemberwiseClone的实现将为您的代码执行以下操作。

 Person p = new Person(); p.Age = this.Age; // value copy p.Name = this.Name; // value copy p.IdInfo = this.IdInfo; // reference copy. this object is the same in both coppies. return p; 

你的新方法不会复制this.Age和this.Name的值,所以我认为它甚至不会被称为副本。

您的DeepCopy不会复制正在复制的对象的年龄和名称字段。 它们将获得默认(T)值(Age = 0,Name = null)。

MemberwiseClone 确实像你一样创建了一个新对象,但它也复制了这些字段:

Person other = new Person();

other.Age = this.Age;

other.Name = this.Name;

由于int是值类型,因此它将被复制到新对象。 Name字段将引用Name引用的相同字符串 – 如果不合适则需要克隆()并在DeepCopy()方法中设置引用,就像IdInfo一样。

根据MSDN :MemberwiseClone方法通过创建新对象创建浅拷贝,然后将当前对象的非静态字段复制到新对象。

其他替代对象扩展是下一个:

 public static class ObjectExtension { public static T Copy(this T lObjSource) { T lObjCopy = (T)Activator.CreateInstance(typeof(T)); foreach (PropertyInfo lObjCopyProperty in lObjCopy.GetType().GetProperties()) { lObjCopyProperty.SetValue ( lObjCopy, lObjSource.GetType().GetProperties().Where(x => x.Name == lObjCopyProperty.Name).FirstOrDefault().GetValue(lObjSource) ); } return lObjCopy; } } 

用来:

 User lObjUserCopy = lObjUser.Copy();