浅复制 - 深复制

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

 

  

posted @ 2016-10-18 22:49  万箭穿心,习惯就好。  阅读(139)  评论(0编辑  收藏  举报