詳解 c# 克隆
克隆方法是原型設(shè)計(jì)模式中必須使用的方式,它將返回一個(gè)與當(dāng)前對(duì)象數(shù)據(jù)一致的對(duì)象。正如其名,猶如一個(gè)模子雕刻而出??寺☆?lèi)型分為兩種:淺克隆、深克隆。
1、淺克隆
淺克隆方式是最簡(jiǎn)單、最直接的方式。只需要類(lèi)實(shí)現(xiàn)接口ICloneable(在命名空間System.Runtime.InteropServices下)的Clone方法,在方法中使用加入對(duì)當(dāng)前類(lèi)的MemberwiseClone()方法即可。在淺克隆中,如果原型對(duì)象的成員變量是值類(lèi)型,將復(fù)制一份給克隆對(duì)象;如果原型對(duì)象的成員變量是引用類(lèi)型,則將引用對(duì)象的地址復(fù)制一份給克隆對(duì)象。
如:
public class Student:ICloneable { /// <summary> /// 值類(lèi)型 /// </summary> public int ID { get; set; } /// <summary> /// 引用類(lèi)型 /// </summary> public object obj { get; set; } public object Clone() { return this.MemberwiseClone(); } }
以上方法實(shí)現(xiàn)了對(duì)類(lèi)對(duì)象的淺克隆方式。但是在該類(lèi)中具有引用類(lèi)型字段,淺克隆方法無(wú)法對(duì)引用字段進(jìn)行克隆,引用字段僅僅是對(duì)其進(jìn)行了地址引用。所以,當(dāng)修改原本或者副本的引用字段的數(shù)據(jù)時(shí),另一個(gè)對(duì)象的引用對(duì)象的數(shù)據(jù)同樣會(huì)變化。深克隆將有效的解決此問(wèn)題。
2、深克隆
深克隆相對(duì)于淺克隆方式比較復(fù)雜。深克隆是無(wú)論原型對(duì)象的成員變量是值類(lèi)型還是引用類(lèi)型,都將復(fù)制一份給克隆對(duì)象,深克隆將原型對(duì)象的所有引用對(duì)象也復(fù)制一份給克隆對(duì)象。
深克隆實(shí)現(xiàn)的機(jī)制是將對(duì)象進(jìn)行序列化為數(shù)據(jù)后,再次將數(shù)據(jù)反序列化為新的對(duì)象。序列化就是將對(duì)象寫(xiě)到流的過(guò)程,寫(xiě)到流中的對(duì)象是原有對(duì)象的一個(gè)拷貝,而原對(duì)象仍然存在于內(nèi)存中。通過(guò)序列化實(shí)現(xiàn)的拷貝不僅可以復(fù)制對(duì)象本身,而且可以復(fù)制其引用的成員對(duì)象,因此通過(guò)序列化將對(duì)象寫(xiě)到一個(gè)流中,再?gòu)牧骼飳⑵渥x出來(lái),可以實(shí)現(xiàn)深克隆。注意,在實(shí)現(xiàn)序列化前需要在類(lèi)的上方標(biāo)記為可序列化。本文采用的序列化方式為二進(jìn)制序列化。
主要實(shí)現(xiàn)的代碼如下:
[Serializable]//標(biāo)記特性:可序列化 public class Student { /// <summary> /// 值類(lèi)型 /// </summary> public int ID { get; set; } /// <summary> /// 引用類(lèi)型 /// </summary> public object obj { get; set; } public Student Clone( ) { Student clone = new Student(); using (Stream stream = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); try { formatter.Serialize(stream, this); stream.Seek(0, SeekOrigin.Begin); clone = formatter.Deserialize(stream) as Student; } catch (SerializationException e) { Console.WriteLine("Failed to serialize. Reason: " + e.Message); throw; } } return clone; } }
深克隆實(shí)現(xiàn)機(jī)制相對(duì)復(fù)雜、效率稍慢,但它克服了淺克隆方式的不足,使得克隆對(duì)象時(shí)將類(lèi)中的引用類(lèi)型數(shù)據(jù)完全克隆為新的對(duì)象,而不是引用原本中的對(duì)象。如此,在修改雙方的引用類(lèi)型對(duì)象的數(shù)據(jù)時(shí)不會(huì)對(duì)另一方造成干擾。
但為每一個(gè)類(lèi)都實(shí)現(xiàn)克隆方式,而重復(fù)書(shū)寫(xiě)相同代碼未免麻煩。因此引入泛型方法。
3、泛型方法實(shí)現(xiàn)克隆
泛型的出現(xiàn)使得可以良好的解決在多個(gè)類(lèi)或結(jié)構(gòu)體中都需要進(jìn)行克隆時(shí)重復(fù)編寫(xiě)代碼的麻煩。在外部只需要使用相關(guān)方法即可。其代碼如下:
public class Clone { /// <summary> /// 深克隆 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <returns></returns> public static T DepthClone<T>(T t) { T clone = default(T); using (Stream stream = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); try { formatter.Serialize(stream, t); stream.Seek(0, SeekOrigin.Begin); clone = (T)formatter.Deserialize(stream); } catch (SerializationException e) { Console.WriteLine("Failed to serialize. Reason: " + e.Message); throw; } } return clone; } }
在外部使用的方法如下:
Student stu1 = new Student();//實(shí)例化一個(gè)對(duì)象 stu1.obj = new object();//實(shí)例化對(duì)象中的引用對(duì)象 Student stu2 = Clone.DepthClone(stu1);//深克隆對(duì)象
4、擴(kuò)展方法
擴(kuò)展方法的出現(xiàn)可以很好的解決類(lèi)自身直接調(diào)用克隆方法,而不需要調(diào)用靜態(tài)類(lèi)的方法,返回對(duì)象值。但其本身與泛型方法類(lèi)似,不過(guò)為了使所有類(lèi)都能使用定義的深克隆方法,此處使用對(duì)頂級(jí)類(lèi)Object進(jìn)行方法的擴(kuò)展,其返回的值也是object類(lèi)型。具體方法如下:
/// <summary> /// 注:擴(kuò)展方法必須在靜態(tài)類(lèi)中 /// </summary> public static class Clone { /// <summary> /// 深克隆 /// </summary> /// <param name="obj">原始版本對(duì)象</param> /// <returns>深克隆后的對(duì)象</returns> public static object DepthClone(this object obj) { object clone = new object(); using (Stream stream = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); try { formatter.Serialize(stream, obj); stream.Seek(0, SeekOrigin.Begin); clone = formatter.Deserialize(stream); } catch (SerializationException e) { Console.WriteLine("Failed to serialize. Reason: " + e.Message); throw; } } return clone; } }
使用方法示例:
Student stu1 = new Student();//實(shí)例化一個(gè)對(duì)象 stu1.obj = new object();//實(shí)例化對(duì)象中的引用對(duì)象 Student stu2 = stu1.DepthClone() as Student;//深克隆對(duì)象;注意:在此需要將object對(duì)象轉(zhuǎn)換為我們需要的對(duì)象類(lèi)型
以上就是詳解 c# 克隆的詳細(xì)內(nèi)容,更多關(guān)于c# 克隆的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
WPF利用WindowChrome實(shí)現(xiàn)自定義窗口
這篇文章主要為大家詳細(xì)介紹了WPF如何利用WindowChrome實(shí)現(xiàn)自定義窗口,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-02-02C#用表達(dá)式樹(shù)構(gòu)建動(dòng)態(tài)查詢(xún)的方法
這篇文章主要介紹了C#用表達(dá)式樹(shù)構(gòu)建動(dòng)態(tài)查詢(xún)的方法,幫助大家更好的理解和學(xué)習(xí)c#,感興趣的朋友可以了解下2020-12-12C# Fiddler插件實(shí)現(xiàn)網(wǎng)站離線(xiàn)瀏覽功能
本文主要介紹了C# Fiddler插件實(shí)現(xiàn)網(wǎng)站離線(xiàn)瀏覽功能的原理與方法。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02C#調(diào)用sql2000存儲(chǔ)過(guò)程方法小結(jié)
這篇文章主要介紹了C#調(diào)用sql2000存儲(chǔ)過(guò)程的方法,以實(shí)例形式分別對(duì)調(diào)用帶輸入?yún)?shù)及輸出參數(shù)的存儲(chǔ)過(guò)程進(jìn)行了詳細(xì)分析,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10