簡(jiǎn)單談?wù)凜#中深拷貝、淺拷貝
Object.MemberwiseClone 方法
創(chuàng)建當(dāng)前 Object 的淺表副本。
protected Object MemberwiseClone()
MemberwiseClone 方法創(chuàng)建一個(gè)淺表副本,方法是創(chuàng)建一個(gè)新對(duì)象,然后將當(dāng)前對(duì)象的非靜態(tài)字段復(fù)制到該新對(duì)象。 如果字段是值類型的,則對(duì)該字段執(zhí)行逐位復(fù)制。 如果字段是引用類型,則復(fù)制引用但不復(fù)制引用的對(duì)象;因此,原始對(duì)象及其復(fù)本引用同一對(duì)象。
例如,考慮對(duì)象X引用對(duì)象 A 和 B , 對(duì)象 B 依次引用對(duì)象 C。 X 的淺表副本創(chuàng)建一個(gè)新對(duì)象 X2,該對(duì)象也引用對(duì)象 A 和 B。 相比而言,X 的深層副本創(chuàng)建一個(gè)新對(duì)象 X2,該對(duì)象引用新對(duì)象 A2 和 B2(分別為 A 和 B 的副本)。 B2 又引用新對(duì)象 C2,C2 是 C 的副本。 該示例闡釋了淺層和深層復(fù)制操作之間的區(qū)別。

有很多方法可以實(shí)現(xiàn)深層復(fù)制操作,前提是淺表復(fù)制操作由 MemberwiseClone 方法執(zhí)行但不符合您的需求。
這些要求包括:
調(diào)用要復(fù)制的對(duì)象的類構(gòu)造函數(shù)以創(chuàng)建含有從第一個(gè)對(duì)象中提出的屬性值的第二個(gè)對(duì)象。 這假定對(duì)象的值完全由類構(gòu)造函數(shù)定義。
調(diào)用 MemberwiseClone 方法創(chuàng)建的對(duì)象的淺表副本,然后將指定新的對(duì)象,其值均相同,原始對(duì)象的任何屬性或字段的值是引用類型。 該示例中的 DeepCopy 方法闡釋了這種方法。
序列化要深層復(fù)制的對(duì)象,然后將序列化的數(shù)據(jù)還原到另一個(gè)對(duì)象變量。
使用帶遞歸的反射執(zhí)行的深層復(fù)制操作。
下面的示例演示 MemberwiseClone 方法。 它定義了 ShallowCopy 方法,該方法通過(guò)調(diào)用 MemberwiseClone 方法來(lái)在 Person 對(duì)象上執(zhí)行淺表復(fù)制操作。 它還定義了在 Person 對(duì)象上執(zhí)行深層復(fù)制操作的DeepCopy 方法。
using System;
public class IdInfo
{
public int IdNumber;
public IdInfo(int IdNumber)
{
this.IdNumber = IdNumber;
}
}
public class Person
{
public int Age;
public string Name;
public IdInfo IdInfo;
public Person ShallowCopy()
{
return (Person)this.MemberwiseClone();
}
public Person DeepCopy()
{
Person other = (Person) this.MemberwiseClone();
other.IdInfo = new IdInfo(this.IdInfo.IdNumber);
return other;
}
}
public class Example
{
public static void Main()
{
// Create an instance of Person and assign values to its fields.
Person p1 = new Person();
p1.Age = 42;
p1.Name = "Sam";
p1.IdInfo = new IdInfo(6565);
// Perform a shallow copy of p1 and assign it to p2.
Person p2 = (Person) p1.ShallowCopy();
// Display values of p1, p2
Console.WriteLine("Original values of p1 and p2:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2);
// Change the value of p1 properties and display the values of p1 and p2.
p1.Age = 32;
p1.Name = "Frank";
p1.IdInfo.IdNumber = 7878;
Console.WriteLine("\nValues of p1 and p2 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p2 instance values:");
DisplayValues(p2);
// Make a deep copy of p1 and assign it to p3.
Person p3 = p1.DeepCopy();
// Change the members of the p1 class to new values to show the deep copy.
p1.Name = "George";
p1.Age = 39;
p1.IdInfo.IdNumber = 8641;
Console.WriteLine("\nValues of p1 and p3 after changes to p1:");
Console.WriteLine(" p1 instance values: ");
DisplayValues(p1);
Console.WriteLine(" p3 instance values:");
DisplayValues(p3);
}
public static void DisplayValues(Person p)
{
Console.WriteLine(" Name: {0:s}, Age: {1:d}", p.Name, p.Age);
Console.WriteLine(" Value: {0:d}", p.IdInfo.IdNumber);
}
}
// The example displays the following output:
// Original values of p1 and p2:
// p1 instance values:
// Name: Sam, Age: 42
// Value: 6565
// p2 instance values:
// Name: Sam, Age: 42
// Value: 6565
//
// Values of p1 and p2 after changes to p1:
// p1 instance values:
// Name: Frank, Age: 32
// Value: 7878
// p2 instance values:
// Name: Sam, Age: 42
// Value: 7878
//
// Values of p1 and p3 after changes to p1:
// p1 instance values:
// Name: George, Age: 39
// Value: 8641
// p3 instance values:
// Name: Frank, Age: 32
// Value: 7878
為了實(shí)現(xiàn)深度復(fù)制,我們就必須遍歷有相互引用的對(duì)象構(gòu)成的圖,并需要處理其中的循環(huán)引用結(jié)構(gòu)。這無(wú)疑是十分復(fù)雜的。幸好借助.Net的序列化和反序列化機(jī)制,可以十分簡(jiǎn)單的深度Clone一個(gè)對(duì)象。
原理很簡(jiǎn)單,首先將對(duì)象序列化到內(nèi)存流中,此時(shí)對(duì)象和對(duì)象引用的所用對(duì)象的狀態(tài)都被保存到內(nèi)存中。.Net的序列化機(jī)制會(huì)自動(dòng)處理循環(huán)引用的情況。然后將內(nèi)存流中的狀態(tài)信息反序列化到一個(gè)新的對(duì)象中。
這樣一個(gè)對(duì)象的深度復(fù)制就完成了。在原型設(shè)計(jì)模式中CLONE技術(shù)非常關(guān)鍵。
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace CloneDemo
{
[Serializable]
class DemoClass
{
public int i = 0;
public int[] iArr = { 1, 2, 3 };
public DemoClass Clone1() //淺CLONE
{
return this.MemberwiseClone() as DemoClass;
}
public DemoClass Clone2() //深clone
{
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0;
return formatter.Deserialize(stream) as DemoClass;
}
}
class Program
{
static void Main(string[] args)
{
DemoClass a = new DemoClass();
a.i = 10;
a.iArr = new int[] { 8, 9, 10 };
DemoClass b = a.Clone1();
DemoClass c = a.Clone2();
// 更改 a 對(duì)象的iArr[0], 導(dǎo)致 b 對(duì)象的iArr[0] 也發(fā)生了變化 而 c不會(huì)變化
a.iArr[0] = 88;
Console.WriteLine("MemberwiseClone");
Console.WriteLine(b.i);
foreach (var item in b.iArr)
{
Console.WriteLine(item);
}
Console.WriteLine("Clone2");
Console.WriteLine(c.i);
foreach (var item in c.iArr)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
}
}
以上所述就是本文的全部?jī)?nèi)容了,希望大家能夠喜歡。
相關(guān)文章
C#設(shè)計(jì)模式之Visitor訪問(wèn)者模式解決長(zhǎng)隆歡樂(lè)世界問(wèn)題實(shí)例
C#通過(guò)yield實(shí)現(xiàn)數(shù)組全排列的方法
c#使用DotNetZip封裝類操作zip文件(創(chuàng)建/讀取/更新)實(shí)例

