长期的答案是“这取决于”。正如其他人所提到的,泛型不支持IC的,循环类引用需要特殊考虑,并且实际上被一些人视为. NET Framework中的“错误”。序列化方法取决于你的对象是可序列化的,而它们可能不是,你可能无法控制。社区中关于哪个是“最佳”实践仍然有很多争论。实际上,没有一个解决方案是适用于所有情况的一刀切的最佳实践,就像IC的最初解释那样。
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 via serialization./// </summary>/// <typeparam name="T">The type of object being copied.</typeparam>/// <param name="source">The object instance to copy.</param>/// <returns>A deep copy of the 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 objectif (ReferenceEquals(source, null)) return default;
using var Stream stream = new MemoryStream();IFormatter formatter = new BinaryFormatter();formatter.Serialize(stream, source);stream.Seek(0, SeekOrigin.Begin);return (T)formatter.Deserialize(stream);}}
/// <summary>/// Perform a deep Copy of the object, using Json as a serialization 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 objectif (ReferenceEquals(source, null)) return default;
// 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 resultvar deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);}
static public IEnumerable<SpotPlacement> CloneList(List<SpotPlacement> spotPlacements){foreach (SpotPlacement sp in spotPlacements){yield return (SpotPlacement)sp.Clone();}}
在另一个地方:
public object Clone(){OrderItem newOrderItem = new OrderItem();...newOrderItem._exactPlacements.AddRange(SpotPlacement.CloneList(_exactPlacements));...return newOrderItem;}
我试图想出一个这样做的oneliner,但这是不可能的,因为在匿名方法块中不工作。
更好的是,使用泛型List克隆器:
class Utility<T> where T : ICloneable{static public IEnumerable<T> CloneList(List<T> tl){foreach (T t in tl){yield return (T)t.Clone();}}}
public static void CopyTo( this object S, object T ){foreach( var pS in S.GetType().GetProperties() ){foreach( var pT in T.GetType().GetProperties() ){if( pT.Name != pS.Name ) continue;( pT.GetSetMethod() ).Invoke( T, new object[]{ pS.GetGetMethod().Invoke( S, null ) } );}};}
public static object CloneObject(object opSource){//grab the type and create a new instance of that typeType opSourceType = opSource.GetType();object opTarget = CreateInstanceOfType(opSourceType);
//grab the propertiesPropertyInfo[] opPropertyInfo = opSourceType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
//iterate over the properties and if it has a 'set' method assign it from the source TO the targetforeach (PropertyInfo item in opPropertyInfo){if (item.CanWrite){//value types can simply be 'set'if (item.PropertyType.IsValueType || item.PropertyType.IsEnum || item.PropertyType.Equals(typeof(System.String))){item.SetValue(opTarget, item.GetValue(opSource, null), null);}//object/complex types need to recursively call this method until the end of the tree is reachedelse{object opPropertyValue = item.GetValue(opSource, null);if (opPropertyValue == null){item.SetValue(opTarget, null, null);}else{item.SetValue(opTarget, CloneObject(opPropertyValue), null);}}}}//return the new itemreturn opTarget;}
public class Person : ICloneable{private final Brain brain; // brain is final since I do not want// any transplant on it once created!private int age;public Person(Brain aBrain, int theAge){brain = aBrain;age = theAge;}protected Person(Person another){Brain refBrain = null;try{refBrain = (Brain) another.brain.clone();// You can set the brain in the constructor}catch(CloneNotSupportedException e) {}brain = refBrain;age = another.age;}public String toString(){return "This is person with " + brain;// Not meant to sound rude as it reads!}public Object clone(){return new Person(this);}…}
现在考虑从Person派生一个类。
public class SkilledPerson extends Person{private String theSkills;public SkilledPerson(Brain aBrain, int theAge, String skills){super(aBrain, theAge);theSkills = skills;}protected SkilledPerson(SkilledPerson another){super(another);theSkills = another.theSkills;}
public Object clone(){return new SkilledPerson(this);}public String toString(){return "SkilledPerson: " + super.toString();}}
您可以尝试运行以下代码:
public class User{public static void play(Person p){Person another = (Person) p.clone();System.out.println(p);System.out.println(another);}public static void main(String[] args){Person sam = new Person(new Brain(), 1);play(sam);SkilledPerson bob = new SkilledPerson(new SmarterBrain(), 1, "Writer");play(bob);}}
产出将是:
This is person with Brain@1fcc69This is person with Brain@253498SkilledPerson: This is person with SmarterBrain@1fef6fSkilledPerson: This is person with SmarterBrain@209f4e
public static T Clone<T>(T source){var serialized = JsonConvert.SerializeObject(source);return JsonConvert.DeserializeObject<T>(serialized);}
此外,您可以使用此扩展方法
public static class SystemExtension{public static T Clone<T>(this T source){var serialized = JsonConvert.SerializeObject(source);return JsonConvert.DeserializeObject<T>(serialized);}}
public static class ObjectCopier{
/// <summary>/// Perform a deep Copy of an object that is marked with '[Serializable]' or '[DataContract]'/// </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 == true){return CloneUsingSerializable<T>(source);}
if (IsDataContract(typeof(T)) == true){return CloneUsingDataContracts<T>(source);}
throw new ArgumentException("The type must be Serializable or use DataContracts.", "source");}
/// <summary>/// Perform a deep Copy of an object that is marked with '[Serializable]'/// </summary>/// <remarks>/// Found on http://stackoverflow.com/questions/78536/cloning-objects-in-c-sharp/// Uses code found on CodeProject, which allows free use in third party apps/// - http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx/// </remarks>/// <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 CloneUsingSerializable<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 objectif (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);}}
/// <summary>/// Perform a deep Copy of an object that is marked with '[DataContract]'/// </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 CloneUsingDataContracts<T>(T source){if (IsDataContract(typeof(T)) == false){throw new ArgumentException("The type must be a data contract.", "source");}
// ** Don't serialize a null object, simply return the default for that objectif (Object.ReferenceEquals(source, null)){return default(T);}
DataContractSerializer dcs = new DataContractSerializer(typeof(T));using(Stream stream = new MemoryStream()){using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream)){dcs.WriteObject(writer, source);writer.Flush();stream.Seek(0, SeekOrigin.Begin);using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max)){return (T)dcs.ReadObject(reader);}}}}
/// <summary>/// Helper function to check if a class is a [DataContract]/// </summary>/// <param name="type">The type of the object to check.</param>/// <returns>Boolean flag indicating if the class is a DataContract (true) or not (false) </returns>public static bool IsDataContract(Type type){object[] attributes = type.GetCustomAttributes(typeof(DataContractAttribute), false);return attributes.Length == 1;}
}
T t = new T();T t2 = (T)t; //eh something like that
List<myclass> cloneum;public void SomeFuncB(ref List<myclass> _mylist){cloneum = new List<myclass>();cloneum = (List < myclass >) _mylist;cloneum.Add(new myclass(3));_mylist = new List<myclass>();}
public AnyObject(AnyObject anyObject){foreach (var property in typeof(AnyObject).GetProperties()){property.SetValue(this, property.GetValue(anyObject));}foreach (var field in typeof(AnyObject).GetFields()){field.SetValue(this, field.GetValue(anyObject));}}
static public MyClass Clone(MyClass myClass){MyClass clone;XmlSerializer ser = new XmlSerializer(typeof(MyClass), _xmlAttributeOverrides);using (var ms = new MemoryStream()){ser.Serialize(ms, myClass);ms.Position = 0;clone = (MyClass)ser.Deserialize(ms);}return clone;}
using System;using System.Collections;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Reflection;using System.Text;
namespace TestDeepClone{class Program{static void Main(string[] args){A a = new A();a.name = "main_A";a.b_list.Add(new B(a) { name = "b1" });a.b_list.Add(new B(a) { name = "b2" });
A a2 = (A)a.DeepClone();a2.name = "second_A";
// Perform re-parenting manually after deep copy.foreach( var b in a2.b_list )b.parent = a2;
Debug.WriteLine("ok");
}}
public class A{public String name = "one";public List<String> list = new List<string>();public List<String> null_list;public List<B> b_list = new List<B>();private int private_pleaseCopyMeAsWell = 5;
public override string ToString(){return "A(" + name + ")";}}
public class B{public B() { }public B(A _parent) { parent = _parent; }public A parent;public String name = "two";}
public static class ReflectionEx{public static Type GetUnderlyingType(this MemberInfo member){Type type;switch (member.MemberType){case MemberTypes.Field:type = ((FieldInfo)member).FieldType;break;case MemberTypes.Property:type = ((PropertyInfo)member).PropertyType;break;case MemberTypes.Event:type = ((EventInfo)member).EventHandlerType;break;default:throw new ArgumentException("member must be if type FieldInfo, PropertyInfo or EventInfo", "member");}return Nullable.GetUnderlyingType(type) ?? type;}
/// <summary>/// Gets fields and properties into one array./// Order of properties / fields will be preserved in order of appearance in class / struct. (MetadataToken is used for sorting such cases)/// </summary>/// <param name="type">Type from which to get</param>/// <returns>array of fields and properties</returns>public static MemberInfo[] GetFieldsAndProperties(this Type type){List<MemberInfo> fps = new List<MemberInfo>();fps.AddRange(type.GetFields());fps.AddRange(type.GetProperties());fps = fps.OrderBy(x => x.MetadataToken).ToList();return fps.ToArray();}
public static object GetValue(this MemberInfo member, object target){if (member is PropertyInfo){return (member as PropertyInfo).GetValue(target, null);}else if (member is FieldInfo){return (member as FieldInfo).GetValue(target);}else{throw new Exception("member must be either PropertyInfo or FieldInfo");}}
public static void SetValue(this MemberInfo member, object target, object value){if (member is PropertyInfo){(member as PropertyInfo).SetValue(target, value, null);}else if (member is FieldInfo){(member as FieldInfo).SetValue(target, value);}else{throw new Exception("destinationMember must be either PropertyInfo or FieldInfo");}}
/// <summary>/// Deep clones specific object./// Analogue can be found here: https://stackoverflow.com/questions/129389/how-do-you-do-a-deep-copy-an-object-in-net-c-specifically/// This is now improved version (list support added)/// </summary>/// <param name="obj">object to be cloned</param>/// <returns>full copy of object.</returns>public static object DeepClone(this object obj){if (obj == null)return null;
Type type = obj.GetType();
if (obj is IList){IList list = ((IList)obj);IList newlist = (IList)Activator.CreateInstance(obj.GetType(), list.Count);
foreach (object elem in list)newlist.Add(DeepClone(elem));
return newlist;} //if
if (type.IsValueType || type == typeof(string)){return obj;}else if (type.IsArray){Type elementType = Type.GetType(type.FullName.Replace("[]", string.Empty));var array = obj as Array;Array copied = Array.CreateInstance(elementType, array.Length);
for (int i = 0; i < array.Length; i++)copied.SetValue(DeepClone(array.GetValue(i)), i);
return Convert.ChangeType(copied, obj.GetType());}else if (type.IsClass){object toret = Activator.CreateInstance(obj.GetType());
MemberInfo[] fields = type.GetFieldsAndProperties();foreach (MemberInfo field in fields){// Don't clone parent back-reference classes. (Using special kind of naming 'parent'// to indicate child's parent class.if (field.Name == "parent"){continue;}
object fieldValue = field.GetValue(obj);
if (fieldValue == null)continue;
field.SetValue(toret, DeepClone(fieldValue));}
return toret;}else{// Don't know that type, don't know how to clone it.if (Debugger.IsAttached)Debugger.Break();
return null;}} //DeepClone}
}
Demo 1 of shallow and deep copy, using classes and MemberwiseClone:Create BobBob.Age=30, Bob.Purchase.Description=LamborghiniClone Bob >> BobsSonAdjust BobsSon detailsBobsSon.Age=2, BobsSon.Purchase.Description=Toy carProof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:Bob.Age=30, Bob.Purchase.Description=LamborghiniElapsed time: 00:00:04.7795670,30000000
Demo 2 of shallow and deep copy, using structs and value copying:Create BobBob.Age=30, Bob.Purchase.Description=LamborghiniClone Bob >> BobsSonAdjust BobsSon details:BobsSon.Age=2, BobsSon.Purchase.Description=Toy carProof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:Bob.Age=30, Bob.Purchase.Description=LamborghiniElapsed time: 00:00:01.0875454,30000000
Demo 3 of deep copy, using class and serialize/deserialize:Elapsed time: 00:00:39.9339425,30000000
要了解如何使用MemberwiseCopy进行深度复制,以下是用于生成上述时间的演示项目:
// Nested MemberwiseClone example.// Added to demo how to deep copy a reference class.[Serializable] // Not required if using MemberwiseClone, only used for speed comparison using serialization.public class Person{public Person(int age, string description){this.Age = age;this.Purchase.Description = description;}[Serializable] // Not required if using MemberwiseClonepublic class PurchaseType{public string Description;public PurchaseType ShallowCopy(){return (PurchaseType)this.MemberwiseClone();}}public PurchaseType Purchase = new PurchaseType();public int Age;// Add this if using nested MemberwiseClone.// This is a class, which is a reference type, so cloning is more difficult.public Person ShallowCopy(){return (Person)this.MemberwiseClone();}// Add this if using nested MemberwiseClone.// This is a class, which is a reference type, so cloning is more difficult.public Person DeepCopy(){// Clone the root ...Person other = (Person) this.MemberwiseClone();// ... then clone the nested class.other.Purchase = this.Purchase.ShallowCopy();return other;}}// Added to demo how to copy a value struct (this is easy - a deep copy happens by default)public struct PersonStruct{public PersonStruct(int age, string description){this.Age = age;this.Purchase.Description = description;}public struct PurchaseType{public string Description;}public PurchaseType Purchase;public int Age;// This is a struct, which is a value type, so everything is a clone by default.public PersonStruct ShallowCopy(){return (PersonStruct)this;}// This is a struct, which is a value type, so everything is a clone by default.public PersonStruct DeepCopy(){return (PersonStruct)this;}}// Added only for a speed comparison.public class MyDeepCopy{public static T DeepCopy<T>(T obj){object result = null;using (var ms = new MemoryStream()){var formatter = new BinaryFormatter();formatter.Serialize(ms, obj);ms.Position = 0;result = (T)formatter.Deserialize(ms);ms.Close();}return (T)result;}}
然后,从main调用demo:
void MyMain(string[] args)\{\{Console.Write("Demo 1 of shallow and deep copy, using classes and MemberwiseCopy:\n");var Bob = new Person(30, "Lamborghini");Console.Write(" Create Bob\n");Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);Console.Write(" Clone Bob >> BobsSon\n");var BobsSon = Bob.DeepCopy();Console.Write(" Adjust BobsSon details\n");BobsSon.Age = 2;BobsSon.Purchase.Description = "Toy car";Console.Write(" BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);Console.Write(" Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);Debug.Assert(Bob.Age == 30);Debug.Assert(Bob.Purchase.Description == "Lamborghini");var sw = new Stopwatch();sw.Start();int total = 0;for (int i = 0; i < 100000; i++){var n = Bob.DeepCopy();total += n.Age;}Console.Write(" Elapsed time: {0},{1}\n\n", sw.Elapsed, total);}{Console.Write("Demo 2 of shallow and deep copy, using structs:\n");var Bob = new PersonStruct(30, "Lamborghini");Console.Write(" Create Bob\n");Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);Console.Write(" Clone Bob >> BobsSon\n");var BobsSon = Bob.DeepCopy();Console.Write(" Adjust BobsSon details:\n");BobsSon.Age = 2;BobsSon.Purchase.Description = "Toy car";Console.Write(" BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);Console.Write(" Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");Console.Write(" Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);Debug.Assert(Bob.Age == 30);Debug.Assert(Bob.Purchase.Description == "Lamborghini");var sw = new Stopwatch();sw.Start();int total = 0;for (int i = 0; i < 100000; i++){var n = Bob.DeepCopy();total += n.Age;}Console.Write(" Elapsed time: {0},{1}\n\n", sw.Elapsed, total);}{Console.Write("Demo 3 of deep copy, using class and serialize/deserialize:\n");int total = 0;var sw = new Stopwatch();sw.Start();var Bob = new Person(30, "Lamborghini");for (int i = 0; i < 100000; i++){var BobsSon = MyDeepCopy.DeepCopy<Person>(Bob);total += BobsSon.Age;}Console.Write(" Elapsed time: {0},{1}\n", sw.Elapsed, total);}Console.ReadKey();}
public static T Clone<T>(this T source){if(Attribute.GetCustomAttribute(typeof(T), typeof(ProtoBuf.ProtoContractAttribute))== null){throw new ArgumentException("Type has no ProtoContract!", "source");}
if(Object.ReferenceEquals(source, null)){return default(T);}
IFormatter formatter = ProtoBuf.Serializer.CreateFormatter<T>();using (Stream stream = new MemoryStream()){formatter.Serialize(stream, source);stream.Seek(0, SeekOrigin.Begin);return (T)formatter.Deserialize(stream);}}
public class Person{[DeepClone(DeepCloneBehavior.Shallow)]private Job _currentJob;
public string Name { get; set; }
public Job CurrentJob{get{ return _currentJob; }set{ _currentJob = value; }}
public Person Manager { get; set; }}
public class Address{public Person PersonLivingHere { get; set; }}
Address adr = new Address();adr.PersonLivingHere = new Person("John");adr.PersonLivingHere.BestFriend = new Person("James");adr.PersonLivingHere.CurrentJob = new Job("Programmer");
Address adrClone = adr.Clone();
//RESULTadr.PersonLivingHere == adrClone.PersonLivingHere //falseadr.PersonLivingHere.Manager == adrClone.PersonLivingHere.Manager //falseadr.PersonLivingHere.CurrentJob == adrClone.PersonLivingHere.CurrentJob //trueadr.PersonLivingHere.CurrentJob.AnyProperty == adrClone.PersonLivingHere.CurrentJob.AnyProperty //true
public partial class Root : ICloneable{public Root(int number){_number = number;}private int _number;
public Partial[] Partials { get; set; }
public IList<ulong> Numbers { get; set; }
public object Clone(){return Clone(true);}
private Root(){}}
public partial class Root{public Root Clone(bool deep){var copy = new Root();// All value types can be simply copiedcopy._number = _number;if (deep){// In a deep clone the references are clonedvar tempPartials = new Partial[Partials.Length];for (var i = 0; i < Partials.Length; i++){var value = Partials[i];value = value.Clone(true);tempPartials[i] = value;}copy.Partials = tempPartials;var tempNumbers = new List<ulong>(Numbers.Count);for (var i = 0; i < Numbers.Count; i++){var value = Numbers[i];tempNumbers.Add(value);}copy.Numbers = tempNumbers;}else{// In a shallow clone only references are copiedcopy.Partials = Partials;copy.Numbers = Numbers;}return copy;}}
public static class CloneThroughJsonExtension{private static readonly JsonSerializerSettings DeserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
public static T CloneThroughJson<T>(this T source){return ReferenceEquals(source, null) ? default(T) : JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), DeserializeSettings);}}
并像这样天真地放弃了课程(事实上还有更多,但它们是不相关的):
public class WhatTheHeck{public string PrivateSet { get; private set; } // matches ctor param name
public string GetOnly { get; } // matches ctor param name
private readonly string _indirectField;public string Indirect => $"Inception of: {_indirectField} "; // matches ctor param namepublic string RealIndirectFieldVaule => _indirectField;
public WhatTheHeck(string privateSet, string getOnly, string indirect){PrivateSet = privateSet;GetOnly = getOnly;_indirectField = indirect;}}
和这样的代码:
var clone = new WhatTheHeck("Private-Set-Prop cloned!", "Get-Only-Prop cloned!", "Indirect-Field clonned!").CloneThroughJson();Console.WriteLine($"1. {clone.PrivateSet}");Console.WriteLine($"2. {clone.GetOnly}");Console.WriteLine($"3.1. {clone.Indirect}");Console.WriteLine($"3.2. {clone.RealIndirectFieldVaule}");
public static class AppExtensions{public static T DeepClone<T>(this T a){using (var stream = new MemoryStream()){var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
serializer.Serialize(stream, a);stream.Position = 0;return (T)serializer.Deserialize(stream);}}}
public class Client{public string Name { get; set; }
protected Client(){}
public static Client Clone(Client copiedClient){return new Client{Name = copiedClient.Name};}}
public class Shop{public string Name { get; set; }
public string Address { get; set; }
public ICollection<Client> Clients { get; set; }
public static Shop Clone(Shop copiedShop, string newAddress, ICollection<Client> clients){var copiedClients = new List<Client>();foreach (var client in copiedShop.Clients){copiedClients.Add(Client.Clone(client));}
return new Shop{Name = copiedShop.Name,Address = newAddress,Clients = copiedClients};}}
static class RandomHelper{private static readonly Random random = new Random();
public static int Next(int maxValue) => random.Next(maxValue);}
class A{private readonly int random = RandomHelper.Next(100);
public override string ToString() => $"{typeof(A).Name}.{nameof(random)} = {random}";}
class B : A{private readonly int random = RandomHelper.Next(100);
public override string ToString() => $"{typeof(B).Name}.{nameof(random)} = {random} {base.ToString()}";}
class C : B{private readonly int random = RandomHelper.Next(100);
public override string ToString() => $"{typeof(C).Name}.{nameof(random)} = {random} {base.ToString()}";}
克隆可以做到:
static class DeepCloneExtension{// consider instance fields, both public and non-publicprivate static readonly BindingFlags bindingFlags =BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
public static T DeepClone<T>(this T obj) where T : new(){var type = obj.GetType();var result = (T)Activator.CreateInstance(type);
do// copy all fieldsforeach (var field in type.GetFields(bindingFlags))field.SetValue(result, field.GetValue(obj));// for every level of hierarchywhile ((type = type.BaseType) != typeof(object));
return result;}}
Demo1:
Console.WriteLine(new C());Console.WriteLine(new C());
var c = new C();Console.WriteLine($"{Environment.NewLine}Image: {c}{Environment.NewLine}");
Console.WriteLine(new C());Console.WriteLine(new C());
Console.WriteLine($"{Environment.NewLine}Clone: {c.DeepClone()}{Environment.NewLine}");
Console.WriteLine(new C());Console.WriteLine(new C());
class D{public event EventHandler Event;public void RaiseEvent() => Event?.Invoke(this, EventArgs.Empty);}
// ...
var image = new D();Console.WriteLine($"Created obj #{image.GetHashCode()}");
image.Event += (sender, e) => Console.WriteLine($"Event from obj #{sender.GetHashCode()}");Console.WriteLine($"Subscribed to event of obj #{image.GetHashCode()}");
image.RaiseEvent();image.RaiseEvent();
var clone = image.DeepClone();Console.WriteLine($"obj #{image.GetHashCode()} cloned to obj #{clone.GetHashCode()}");
clone.RaiseEvent();image.RaiseEvent();
结果:
Created obj #46104728Subscribed to event of obj #46104728Event from obj #46104728Event from obj #46104728obj #46104728 cloned to obj #12289376Event from obj #12289376Event from obj #46104728
public static class Extentions{public static T Clone<T>(this T obj){byte[] buffer = BinarySerialize(obj);return (T)BinaryDeserialize(buffer);}
public static byte[] BinarySerialize(object obj){using (var stream = new MemoryStream()){var formatter = new BinaryFormatter();formatter.Serialize(stream, obj);return stream.ToArray();}}
public static object BinaryDeserialize(byte[] buffer){using (var stream = new MemoryStream(buffer)){var formatter = new BinaryFormatter();return formatter.Deserialize(stream);}}}
该对象必须为序列化过程进行序列化。
[Serializable]public class MyObject{public string Name { get; set; }}
public static T Clone<T>(this T theObject){string jsonData = JsonConvert.SerializeObject(theObject);return JsonConvert.DeserializeObject<T>(jsonData);}
public static T Clone<T>(T source){var serialized = JsonSerializer.Serialize(source);return JsonSerializer.Deserialize<T>(serialized);}
扩展方法:
public static class SystemExtension{public static T Clone<T>(this T source){var serialized = JsonSerializer.Serialize(source);return JsonSerializer.Deserialize<T>(serialized);}}
public static class CloneExtensions{public static T Clone<T>(this T cloneable) where T : new(){var toJson = JsonSerializer.Serialize(cloneable);return JsonSerializer.Deserialize<T>(toJson);}}
using System;
public class Program{public class Example{public string A { get; set; }}
public record ClonerRecord<T>(T a){}
public static void Main(){var foo = new Example {A = "Hello World"};var bar = (new ClonerRecord<Example>(foo) with {}).a;foo.A = "Goodbye World :(";Console.WriteLine(bar.A);}}
using System;
public class Program{public record Example{public string A { get; set; }}
public static void Main(){var foo = new Example {A = "Hello World"};var bar = foo with {};foo.A = "Goodbye World :(";Console.WriteLine(bar.A);}}
英特尔酷睿i5-6200U CPU 2.30GHz(Skylake),1个CPU,4个逻辑内核和2个物理内核[主机]:. NET Framework 4.8(4.8.4400.0),X86 LegacyJIT默认作业:. NET Framework 4.8(4.8.4400.0),X86 LegacyJIT
public abstract class CloneablePrototype<T>{public T DeepCopy(){string result = JsonConvert.SerializeObject(this);return JsonConvert.DeserializeObject<T>(result);}}public class YourClass : CloneablePrototype< YourClass>………
像这样使用它来创建深度副本。
YourClass newObj = (YourClass)oldObj.DeepCopy();
如果您还需要实现浅拷贝方法,这个解决方案也很容易扩展。
只需在抽象类中实现一个新方法。
public T ShallowCopy(){return (T)this.MemberwiseClone();}
using Newtonsoft.Json;
public static T DeepCopy<T>(this T source){return (T)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source), source.GetType());}
using Baksteen.Extensions.DeepCopy;...var myobject = new SomeClass();...var myclone = myobject.DeepCopy()!; // creates a new deep copy of the original object