不忘本~淺拷貝和深拷貝
Clone 分淺拷貝和深拷貝
兩者的區(qū)別:當(dāng)對象中的屬性是引用類型時,即類product中還有對類category的引用時,淺拷貝與深拷貝才有區(qū)別。
淺拷貝:復(fù)制的是category的引用,當(dāng)原對象改變時,會影響新對象,反之,亦然。
深拷貝:復(fù)制的是category的值,即,它會new一個新的category,然后將原來的category元素的值復(fù)制到新元素,即它與原對象沒有任何關(guān)系,只是內(nèi)容相同。
如何實現(xiàn)對象的拷貝功能:
繼承接口ICloneable實現(xiàn)Clone方法
ICloneable.Clone本身并不能區(qū)分(Deep or Shallow)你可以在Clone中調(diào)用MemberwiseClone來實現(xiàn)一個ShallowClone也可以自己來實現(xiàn)一個DeepClone。不過按照microsoft的建議當(dāng)實現(xiàn)ICloneable的時候是準(zhǔn)備用來實現(xiàn)一個DeepClone。
ICloneable.Clone返回類型是object
其中MemberwiseClone的復(fù)制原理是值類型按位復(fù)制,引用類型復(fù)制對象的引用。這里有一個要注意的就是String類型,雖然是引用類型,不過在這里表現(xiàn)上和值類型是一樣的,在Clone的時候就當(dāng)作值類型來看待好了。
實現(xiàn)Clone的方法:
1. 手工克隆
一個能夠保證對象完全按照你所想的那樣進(jìn)行克隆的方式是手工克隆對象的每一個域(field)。這種方式的缺點是麻煩而且容易出錯:如果你在類中增加了一個域,你很可能會忘記更新Clone方法。還要在克隆引用對象指向原始對象的時候,注意避免無限循環(huán)引用。下面是一個進(jìn)行深拷貝的簡單例子:
2. 使用MemberWiseClone方法
MemberWiseClone是 Object類的受保護(hù)方法,能夠通過創(chuàng)建一個新對象,并把所有當(dāng)前對象中的非靜態(tài)域復(fù)制到新對象中,從而創(chuàng)建一個淺拷貝。對于值類型的域,進(jìn)行的是按位拷貝。對于引用類型的域,引用會被賦值而引用的對象則不會。因此,原始對象及其克隆都會引用同一個對象。注意,這種方法對派生類都是有效的,也就是說,你只需在基類中定義一次Clone方法。下面是一個簡單的例子:
1 public class Person : ICloneable 2 { 3 public string Name; 4 public Person Spouse; 5 public object Clone() 6 { 7 return this.MemberwiseClone(); 8 } 9 }
3. 用反射進(jìn)行克隆
用反射進(jìn)行克隆是使用Activator.CreateInstance方法來創(chuàng)建一個相同類型的新對象,然后用反射對所有域進(jìn)行淺拷貝。這種方法的優(yōu)點是它是全自動的,不需要在對象中添加或刪除成員的時候修改克隆方法。另外它也能被寫成提供深拷貝的方法。缺點是使用了反射,因此會比較慢,而且在部分受信任的環(huán)境中是不可用的。示例代碼
4. 使用序列化進(jìn)行克隆
克隆一個對象的最簡單的方法是將它序列化并立刻反序列化為一個新對象。和反射方法一樣,序列化方法是自動的,無需在對對象成員進(jìn)行增刪的時候做出修改。缺點是序列化比其他方法慢,甚至比用反射還慢,所有引用的對象都必須是可序列化的(Serializable)。另外,取決于你所使用的序列化的類型(XML,SOAP,二進(jìn)制)的不同,私有成員可能不能像期望的那樣被克隆。示例代碼在這里,這里和這里。
5. 使用IL進(jìn)行克隆
一種罕見的解決方案是使用IL(中間語言)來進(jìn)行對象克隆。這種方式創(chuàng)建一個動態(tài)方法(DynamicMethod),獲取中間語言生成器(ILGenerator),向方法中注入代碼,把它編譯成一個委托,然后執(zhí)行這個委托。委托會被緩存,因此中間語言只在初次克隆的時候才會生成,后續(xù)的克隆都不會重新生成一遍。盡管這種方法比使用反射快,但是這種方法難以理解和維護(hù)。示例代碼
6. 使用擴(kuò)展方法進(jìn)行克隆
Havard Stranden用擴(kuò)展方法(extention method)創(chuàng)建了一個自定義的克隆框架。這個框架能夠創(chuàng)建對象及其引用的對象的深拷貝,不管對象結(jié)構(gòu)有多復(fù)雜。缺點是,這是一個不提供源代碼的自定義框架(更新:現(xiàn)在已經(jīng)包括源代碼了,參見本文評論),并且它不能在不使用無參數(shù)構(gòu)造器的時候,拷貝由私有方法創(chuàng)建的對象。另一個問題,也是所有自動化的深克隆方法共有的問題是,深拷貝通常需要靈活地處理不能進(jìn)行簡單自動化特殊情況(例如未受管理的資源)。
浙公網(wǎng)安備 33010602011771號