Clone.gif
關(guān)于Clone一般區(qū)分為兩種窝趣,淺拷貝和深拷貝疯暑。
淺拷貝
? 指的是拷貝一個對象的時候,只拷貝對對象的引用哑舒。當你修改一個對象的值后妇拯,另一個對象的值也會改變。在內(nèi)存中引用類型的創(chuàng)建是創(chuàng)建在內(nèi)存堆中洗鸵,而內(nèi)存棧中這是創(chuàng)建一個對內(nèi)存堆中的地址的引用越锈。值類型則是直接在內(nèi)存棧中創(chuàng)建。
.net中實現(xiàn)淺拷貝的內(nèi)置方法(System.Object的方法) MemberwiseClone()膘滨。
例如:
// 將要進行淺度復制的對象,注意為引用類型
public class RefLine : ICloneable
{
public RefPoint rPoint;
public ValPoint vPoint;
public RefLine(RefPoint rPoint, ValPoint vPoint)
{
this.rPoint = rPoint;
this.vPoint = vPoint;
}
public object Clone()
{
return this.MemberwiseClone();//.net中實現(xiàn)淺拷貝的內(nèi)置方法(System.Object的方法)
}
}
// 定義一個引用類型成員
public class RefPoint
{
public int x;
public RefPoint(int x)
{
this.x = x;
}
}
// 定義一個值類型成員
public struct ValPoint
{
public int x;
public ValPoint(int x)
{
this.x = x;
}
}
/// <summary>
/// clone() 方法驗證
/// </summary>
public static void demo2()
{
RefPoint rPoint = new RefPoint(1);
ValPoint vPoint = new ValPoint(1);
RefLine line = new RefLine(rPoint, vPoint);
RefLine newLine = (RefLine)line.Clone();
Console.WriteLine("Original: line.rPoint.x = {0}, line.vPoint.x= {1} ", line.rPoint.x, line.vPoint.x);
Console.WriteLine("Cloned: newLine.rPoint.x = {0}, newLine.vPoint.x = {1} ", newLine.rPoint.x, newLine.vPoint.x);
line.rPoint.x = 10; // 修改原先的line的引用類型成員 rPoint
line.vPoint.x = 10; // 修改原先的line的值類型成員 vPoint
Console.WriteLine("Original: line.rPoint.x = {0}, line.vPoint.x= {1} ", line.rPoint.x, line.vPoint.x);
Console.WriteLine("Cloned: newLine.rPoint.x = {0}, newLine.vPoint.x = {1} ", newLine.rPoint.x, newLine.vPoint.x);
}
static void Main(string[] args) {
demo2();
Console.Read();
}
結(jié)果如下:
ShallowClone.png
深拷貝:
? 指在內(nèi)存堆中又創(chuàng)建一個和你Clone對象一樣的對象甘凭。當你修改了舊對象中的某個值時,新對象也不會變火邓。
? 深拷貝有多種實現(xiàn)方式:
1.深拷貝可以利用序列化反序列化對對象進行深度復制丹弱。
/// <summary>
/// 深拷貝
/// </summary>
/// <returns></returns>
public object Clone()
{
using(var ms = new MemoryStream())
{
var bf = new BinaryFormatter();
bf.Serialize(ms, this);
ms.Seek(0, SeekOrigin.Begin);
return (bf.Deserialize(ms));
}
}
注:使用序列化時記得在類上加上[serializable]的特性
2.利用反射的方式進行深度復制。
public static T DeepCopyByReflect<T>(T obj)
{
//如果是字符串或值類型則直接返回
if (obj is string || obj.GetType().IsValueType) return obj;
object retval = Activator.CreateInstance(obj.GetType());//若obj沒有無參構(gòu)造函數(shù),此語句報錯
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))); }//遞歸下去直到field為值類型或string給其賦值
catch { }
}
return (T)retval;
}
注:使用反射時必須引用類型必須有無參構(gòu)造函數(shù)
兩種方式的結(jié)果相同铲咨,如下: