我想做类似的事情:
MyObject myObj = GetMyObj(); // Create and fill a new object MyObject newObj = myObj.Clone();
然后对未反映在原始对象中的新对象进行更改。
我通常不需要此功能,因此在必要时我会先创建一个新对象,然后分别复制每个属性,但是这总是让我感到有更好或更优雅的处理方式情况。
如何克隆或深度复制对象,以便可以修改克隆的对象而不会在原始对象中反映任何更改?
虽然标准做法是实现ICloneable接口(在此进行描述,所以我不会反驳),但这是我之前在The Code Project上发现的一个不错的深克隆对象复印机,并将其合并到我们的资料中。
ICloneable
如在其他地方提到的,它确实要求您的对象可序列化。
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); } } }
这个想法是先序列化您的对象,然后反序列化为一个新的对象。这样做的好处是,当对象变得太复杂时,您不必担心克隆所有内容。
并使用扩展方法(也来自最初引用的源):
如果您更喜欢使用C#3.0 的新扩展方法,请将方法更改为具有以下签名:
public static T Clone<T>(this T source) { //... }
现在,方法调用简单地变为objectBeingCloned.Clone();。
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); }