Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
367 views
in Technique[技术] by (71.8m points)

c# - 深度克隆对象(Deep cloning objects)

I want to do something like:

(我想做类似的事情:)

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

And then make changes to the new object that are not reflected in the original object.

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

I don't often need this functionality, so when it's been necessary, I've resorted to creating a new object and then copying each property individually, but it always leaves me with the feeling that there is a better or more elegant way of handling the situation.

(我通常不需要此功能,因此在必要时我会先创建一个新对象,然后分别复制每个属性,但是这总是让我感到有更好或更优雅的处理方式情况。)

How can I clone or deep copy an object so that the cloned object can be modified without any changes being reflected in the original object?

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

  ask by NakedBrunch translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Whilst the standard practice is to implement the ICloneable interface (described here , so I won't regurgitate), here's a nice deep clone object copier I found on The Code Project a while ago and incorporated it in our stuff.

(虽然标准做法是实现ICloneable接口( 在此进行了介绍,所以我不会反驳),但我还是在一段时间前在The Code Project上发现了一个不错的深克隆对象复印机,并将其合并到我们的资料中。)

As mentioned elsewhere, it does require your objects to be serializable.

(如在其他地方提到的,它确实要求您的对象可序列化。)

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.", nameof(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);
        }
    }
}

The idea is that it serializes your object and then deserializes it into a fresh object.

(这个想法是先序列化您的对象,然后反序列化为一个新的对象。)

The benefit is that you don't have to concern yourself about cloning everything when an object gets too complex.

(这样做的好处是,当对象变得太复杂时,您不必担心克隆所有内容。)

And with the use of extension methods (also from the originally referenced source):

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

In case you prefer to use the new extension methods of C# 3.0, change the method to have the following signature:

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

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

Now the method call simply becomes objectBeingCloned.Clone();

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

.

(。)

EDIT (January 10 2015) Thought I'd revisit this, to mention I recently started using (Newtonsoft) Json to do this, it should be lighter, and avoids the overhead of [Serializable] tags.

(编辑 (2015年1月10日)以为我会重新审视这一点,我最近提到开始使用(Newtonsoft)Json来做到这一点,它应该更轻巧,并且避免了[Serializable]标签的开销。)

( NB @atconway has pointed out in the comments that private members are not cloned using the JSON method)

(( 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);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...