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;