Shallow Copy
System.Object.MemberwiseClone();受保护的方法。
Deep Copy
实现 ICloneable 接口并重写 Clone() 方法:
public class A : ICloneable{ public A() {} public object Clone() { A objA = new A(); return objA; } }
下面总结了 深拷贝 的几种常用方法
/// BY IFormatter public T DeepCloneObj<T>(T obj) { using (Stream objectStream = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); formatter.Serialize(objectStream, obj); objectStream.Seek(0, SeekOrigin.Begin); object objDeep = formatter.Deserialize(objectStream); return (T)objDeep; } } /// BY BinaryFormatter private static T DeepCopyObj<T>(T obj) { object retObj = null; using (MemoryStream ms = new MemoryStream()) { BinaryFormatter bf = new BinaryFormatter(); //序列化成流 bf.Serialize(ms, obj); ms.Seek(0, SeekOrigin.Begin); //反序列化成对象 retObj = bf.Deserialize(ms); ms.Close(); } return (T)retObj; } /// BY XmlSerializer public static T DeepCopyByXml<T>(T obj) { object retVal; using (MemoryStream ms = new MemoryStream()) { XmlSerializer xml = new XmlSerializer(typeof(T)); xml.Serialize(ms, obj); ms.Seek(0, SeekOrigin.Begin); retVal = xml.Deserialize(ms); ms.Close(); } return (T)retVal; } /// BY DataContractSerializer,需要Silverlight支持 public static T DeepCopy<T>(T obj) { object retval; using (MemoryStream ms = new MemoryStream()) { DataContractSerializer ser = new DataContractSerializer(typeof(T)); ser.WriteObject(ms, obj); ms.Seek(0, SeekOrigin.Begin); retval = ser.ReadObject(ms); ms.Close(); } return (T)retval; } /// BY 反射 public static T DeepCopyByReflect<T>(T obj) { //如果是字符串或值类型则直接返回 if (obj is string || obj.GetType().IsValueType) return obj; object retval = Activator.CreateInstance(obj.GetType()); FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); foreach (FieldInfo field in fields) { try { field.SetValue(retval, DeepCopyByReflect(field.GetValue(obj))); } catch { } } return (T)retval; }
其中,前4种方法类似,最后一种方法是通过反射实现深拷贝。 注意,类对象应该 [Serializable] 标识。
此外,可以通过如下方法,判断前后2个对象地址是否不同
object.ReferenceEquals(per1., per2).ToString() // True or False
也可以分别获取2个对象的地址比较,亦可
/// <summary> /// 获取引用类型的内存地址 /// </summary> /// <param name="obj"></param> /// <returns></returns> public static string getMemAddr(object obj) { GCHandle h = GCHandle.Alloc(obj, GCHandleType.WeakTrackResurrection); IntPtr addr = GCHandle.ToIntPtr(h); return "0x" + addr.ToString("X"); }
除单独的深拷贝方法,也可以直接类对象内部实现
[Serializable] public class D : ICloneable { public object Clone() { return this.MemberwiseClone(); //浅拷贝 } //浅拷贝 public D ShallowClone() { return this.Clone() as D; } //深拷贝 public D DeepClone() { DeepCopyByXXX(); } }
具体参见:C#对象复制 - ICloneable;