深入克隆对象

我想要做一些事情:

MyObject myObj = GetMyObj(); // Create and fill a new object
MyObject newObj = myObj.Clone();

然后对未反映在原始对象中的新对象进行更改。

我不经常需要这个功能,所以当有必要的时候,我已经采取了创建一个新的对象,然后单独复制每个属性,但它总是让我感觉有一种更好或更优雅的处理方式情况。

如何克隆或深度复制对象,以便可以修改克隆的对象,而不会在原始对象中反映任何更改?


虽然标准的做法是实现ICloneable接口(在这里描述,所以我不会反胃),这是一个很好的深层克隆对象复制器,我在The Code Project上找到了它,并将它合并到我们的东西中。

如别处所述,它确实需要您的对象是可序列化的。

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

/// <summary>
/// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// </summary>
public static class ObjectCopier
{
    /// <summary>
    /// Perform a deep Copy of the object.
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T Clone<T>(T source)
    {
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", "source");
        }

        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        IFormatter formatter = new BinaryFormatter();
        Stream stream = new MemoryStream();
        using (stream)
        {
            formatter.Serialize(stream, source);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }
}

这个想法是,它序列化你的对象,然后将它反序列化为一个新的对象。 好处是,当对象变得太复杂时,你不必关心克隆所有东西。

并使用扩展方法(也来自最初引用的来源):

如果您更喜欢使用C#3.0的新扩展方法,请将该方法更改为具有以下签名:

public static T Clone<T>(this T source)
{
   //...
}

现在方法调用变成了objectBeingCloned.Clone();

编辑 (2015年1月10日)以为我会重温这个,提到我最近开始使用(Newtonsoft)Json来做到这一点,它应该更轻,并避免[Serializable]标签的开销。 ( NB @atconway在评论中指出,私有成员不是使用JSON方法克隆的)

/// <summary>
/// Perform a deep Copy of the object, using Json as a serialisation method. NOTE: Private members are not cloned using this method.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T CloneJson<T>(this T source)
{            
    // Don't serialize a null object, simply return the default for that object
    if (Object.ReferenceEquals(source, null))
    {
        return default(T);
    }

    // initialize inner objects individually
    // for example in default constructor some list property initialized with some values,
    // but in 'source' these items are cleaned -
    // without ObjectCreationHandling.Replace default constructor values will be added to result
    var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};

    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}

我想要一个非常简单的对象,主要是原始类和列表的克隆。 如果你的对象是开箱即用的JSON序列化的,那么这个方法就可以做到。 这不需要修改或实现克隆类上的接口,只需要JSON.NET等JSON序列化程序。

public static T Clone<T>(T source)
{
    var serialized = JsonConvert.SerializeObject(source);
    return JsonConvert.DeserializeObject<T>(serialized);
}

不使用ICloneable的原因不是因为它没有一个通用的接口。 不使用它的原因是因为它含糊不清。 它并没有说明你是否得到浅或深的副本; 这取决于实施者。

是的, MemberwiseClone创建一个浅拷贝,但MemberwiseClone的对面不是Clone ; 它可能是DeepClone ,它不存在。 当您通过ICloneable接口使用对象时,无法知道底层对象执行哪种克隆。 (XML注释不会清楚,因为您将获得接口注释而不是对象的Clone方法。)

我通常做的只是制作一个Copy方法,它完全符合我的需求。

链接地址: http://www.djcxy.com/p/1063.html

上一篇: Deep cloning objects

下一篇: Issues with Date() when using JSON.stringify() and JSON.parse()