C#中的深层复制

Kev*_*ith 12 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,是否必须实例化一个新的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

Adr*_*der 12

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

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

来自Object.MemberwiseClone方法

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

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


das*_*ght 6

MemberwiseClone()创建复制类的新实例,还复制标量场进副本的相应成员.它提供了一个更好的深度复制起点,而不仅仅是普通的new,因为你只需要"修复"需要深度复制的项目.


Mat*_*ias 6

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

public static class ObjectExtensions
{
    #region Methods

    public static T Copy<T>(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
}
Run Code Online (Sandbox Code Playgroud)

这也应该复制你的IdInfo领域.

用法很简单:

var copy = obj.Copy();
Run Code Online (Sandbox Code Playgroud)