C# 淺克隆與深克隆
阿新 • • 發佈:2019-02-15
一、淺克隆:
在淺克隆中,如果原型物件的成員變數是值型別,將複製一份給克隆物件;如果原型物件的成員變數是引用型別,則將引用物件的地址複製一份給克隆物件,也就是說原型物件和克隆物件的成員變數指向相同的記憶體地址。簡單來說,在淺克隆中,當物件被複制時只複製它本身和其中包含的值型別的成員變數,而引用型別的成員物件並沒有複製,如圖:
在C#中,通過實現ICloneable介面的Clone方法()呼叫MemberwiseClone方法)來實現淺克隆:
public class WeeklyLog:ICloneable { public string Name { get; set; } public Student Student { get; set; } public object Clone() { return this.MemberwiseClone(); } }
{
public string Address { get; set; }
}
static void Main(string[] args) { WeeklyLog log1 = new ProtoTypeTest.WeeklyLog(); log1.Name = "log1"; log1.Student = new ProtoTypeTest.Student() { Address = "haidian" }; WeeklyLog log2 = (WeeklyLog)log1.Clone();//呼叫淺克隆方法 Console.WriteLine(log1.Name);//log1 Console.WriteLine(log2.Name);//log1 Console.WriteLine(log1.Student.Address);//haidian Console.WriteLine(log2.Student.Address);//haidian Console.WriteLine(object.ReferenceEquals(log1, log2));//false log2.Name = "log2";//修改克隆的物件的name屬性 Console.WriteLine(log1.Name);//log1 Console.WriteLine(log2.Name);//log2 log2.Student.Address = "chaoyang";//修改克隆的物件的引用型別Student的Address屬性 Console.WriteLine(log1.Student.Address);//chaoyang Console.WriteLine(log2.Student.Address);//chaoyang Console.ReadLine(); }
二、深克隆:
在深克隆中,無論原型物件的成員變數是值型別還是引用型別,都將複製一份給克隆物件,深克隆將原型物件的所有引用物件也複製一份給克隆物件。簡單來說,在深克隆中,除了物件本身被複制外,物件所包含的所有成員變數也將複製,如圖:
在C#語言中,如果需要實現深克隆,可以通過序列化(Serialization)等方式來實現。序列化就是將物件寫到流的過程,寫到流中的物件是原有物件的一個拷貝,而原物件仍然存在於記憶體中。通過序列化實現的拷貝不僅可以複製物件本身,而且可以複製其引用的成員物件,因此通過序列化將物件寫到一個流中,再從流裡將其讀出來,可以實現深克隆。需要注意的是能夠實現序列化的物件其類必須實現Serializable介面,否則無法實現序列化操作。下面我們使用深克隆技術來實現工作週報和附件物件的複製,由於要將附件物件和工作週報物件都寫入流中,因此兩個類用Serializable標識可序列化:
[Serializable]
public class WeeklyLog
{
public string Name { get; set; }
public Student Student { get; set; }
public WeeklyLog DeepClone()
{
object obj = null;
//將物件序列化成記憶體中的二進位制流
BinaryFormatter inputFormatter = new BinaryFormatter();
MemoryStream inputStream;
using (inputStream = new MemoryStream())
{
inputFormatter.Serialize(inputStream, this);
}
//將二進位制流反序列化為物件
using (MemoryStream outputStream = new MemoryStream(inputStream.ToArray()))
{
BinaryFormatter outputFormatter = new BinaryFormatter();
obj = outputFormatter.Deserialize(outputStream);
}
return (WeeklyLog)obj;
}
}
[Serializable]
public class Student
{
public string Address { get; set; }
}
<pre name="code" class="csharp"> static void Main(string[] args)
{
WeeklyLog log1 = new ProtoTypeTest.WeeklyLog();
log1.Name = "log1";
log1.Student = new ProtoTypeTest.Student() { Address = "haidian" };
WeeklyLog log2 = (WeeklyLog)log1.DeepClone();//呼叫深克隆方法
Console.WriteLine(log1.Name);//log1
Console.WriteLine(log2.Name);//log1
Console.WriteLine(log1.Student.Address);//haidian
Console.WriteLine(log2.Student.Address);//haidian
Console.WriteLine(object.ReferenceEquals(log1, log2));//false
log2.Name = "log2";//修改克隆的物件的name屬性
Console.WriteLine(log1.Name);//log1
Console.WriteLine(log2.Name);//log2
log2.Student.Address = "chaoyang";//修改克隆的物件的引用型別Student的Address屬性
Console.WriteLine(log1.Student.Address);//haidian
Console.WriteLine(log2.Student.Address);//chaoyang
Console.ReadLine();
}