国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

淺析C#深拷貝與淺拷貝

2019-11-11 04:48:55
字體:
供稿:網(wǎng)友
1.深拷貝與淺拷貝         拷貝即是通常所說的復制(Copy)或克隆(Clone),對象的拷貝也就是從現(xiàn)有對象復制一個“一模一樣”的新對象出來。雖然都是復制對象,但是不同的 復制方法,復制出來的新對象卻并非完全一模一樣,對象內(nèi)部存在著一些差異。通常的拷貝方法有兩種,即深拷貝和淺拷貝,那二者之間有何區(qū)別呢?MSDN里對 IClone接口的Clone方法有這樣的說明:在深層副本中,所有的對象都是重復的;而在淺表副本中,只有頂級對象是重復的,并且頂級以下的對象包含引 用。可以看出,深拷貝和淺拷貝之間的區(qū)別在于是否復制了子對象。這如何理解呢?下面我通過帶有子對象的代碼來驗證二者的區(qū)別。        首先定義兩個類型:Student和ClassRoom,其中Student類型里包含ClassRoom,并使這兩個類型都分別實現(xiàn)自定義的深拷貝接口(IDeepCopy)和淺拷貝接口(IShallowCopy)。類圖如下:

定義代碼如下:

/// <summary>    /// 深拷貝接口    /// </summary>    interface IDeepCopy    {        object DeepCopy();    }    /// <summary>    /// 淺拷貝接口    /// </summary>    interface IShallowCopy    {        object ShallowCopy();    }    /// <summary>    /// 教室信息    /// </summary>    class ClassRoom : IDeepCopy, IShallowCopy    {        public int RoomID = 1;        public string RoomName = "Room1";        public override string ToString()        {            return "RoomID=" + RoomID + "/tRoomName=" + RoomName;        }        public object DeepCopy()        {            ClassRoom r = new ClassRoom();            r.RoomID = this.RoomID;            r.RoomName = this.RoomName;            return r;        }        public object ShallowCopy()        {            //直接使用內(nèi)置的淺拷貝方法返回            return this.MemberwiseClone();        }    }    class Student : IDeepCopy, IShallowCopy    {        //為了簡化,使用public 字段        public string Name;        public int Age;        //自定義類型,假設每個Student只擁有一個ClassRoom        public ClassRoom Room = new ClassRoom();        public Student()        {        }        public Student(string name, int age)        {            this.Name = name;            this.Age = age;        }        public object DeepCopy()        {            Student s = new Student();            s.Name = this.Name;            s.Age = this.Age;            s.Room = (ClassRoom)this.Room.DeepCopy();            return s;        }        public object ShallowCopy()        {            return this.MemberwiseClone();        }        public override string ToString()        {            return "Name:" + Name + "/tAge:" + Age + "/t" + Room.ToString();        }    }pastingpasting測試代碼:

Student s1 = new Student("Vivi", 28); Console.WriteLine("s1=[" + s1 + "]"); Student s2 = (Student)s1.ShallowCopy(); //Student s2 = (Student)s1.DeepCopy(); Console.WriteLine("s2=[" + s2 + "]"); //此處s2和s1內(nèi)容相同 Console.WriteLine("-----------------------------"); //修改s2的內(nèi)容 s2.Name = "tianyue"; s2.Age = 25; s2.Room.RoomID = 2; s2.Room.RoomName = "Room2"; Console.WriteLine("s1=[" + s1 + "]"); Console.WriteLine("s2=[" + s2 + "]"); //再次打印兩個對象以比較 Console.ReadLine();

運行結(jié)果:

a.ShallowCopys1=[Name:Vivi   Age:28  RoomID=1        RoomName=Room1]s2=[Name:Vivi   Age:28  RoomID=1        RoomName=Room1]-------------------------------------------------------------s1=[Name:Vivi   Age:28  RoomID=2        RoomName=Room2]s2=[Name:tianyue        Age:25  RoomID=2        RoomName=Room2]b.DeepCopys1=[Name:Vivi   Age:28  RoomID=1        RoomName=Room1]s2=[Name:Vivi   Age:28  RoomID=1        RoomName=Room1]-----------------------------s1=[Name:Vivi   Age:28  RoomID=1        RoomName=Room1]s2=[Name:tianyue        Age:25  RoomID=2        RoomName=Room2]        從以上結(jié)果可以看出,深拷貝時兩個對象是完全“分離”的,改變其中一個,不會影響到另一個對象;        淺拷貝時兩個對象并未完全“分離”,改變頂級對象的內(nèi)容,不會對另一個對象產(chǎn)生影響,但改變子對象的內(nèi)容,則兩個對象同時被改變。        這種差異的產(chǎn)生,即是取決于拷貝子對象時復制內(nèi)存還是復制指針。       深拷貝為子對象重新分配了一段內(nèi)存空間,并復制其中的內(nèi)容;淺拷貝僅僅將指針指向原來的子對象。示意圖如下:2.淺拷貝與賦值操作        大多數(shù)面向?qū)ο笳Z言中的賦值操作都是傳遞引用,即改變對象的指針地址,而并沒有復制內(nèi)存,也沒有做任何復制操作。       由此可知,淺拷貝與賦值操作的區(qū)別是頂級對象的復制與否。當然,也有一些例外情況,比如類型定義中重載賦值操作符(assignment Operator),或者某些類型約定按值傳遞,就像C#中的結(jié)構(gòu)體和枚舉類型。賦值操作示意圖如下:3.C++拷貝構(gòu)造函數(shù)        與其它面向?qū)ο笳Z言不同,C++允許用戶選擇自定義對象的傳遞方式:值傳遞和引用傳遞。在值傳遞時就要使用對象拷貝,比如說按值傳遞參數(shù),編譯 器需要拷貝一個對象以避免原對象在函數(shù)體內(nèi)被破壞。為此,C++提供了拷貝構(gòu)造函數(shù)用來實現(xiàn)這種拷貝行為,拷貝構(gòu)造函數(shù)是一種特殊的構(gòu)造函數(shù),用來完成一 些基于同一類的其它對象的構(gòu)造和初始化。它唯一的參數(shù)是引用類型的,而且不可改變,通常的定義為X(const X&)。在拷貝構(gòu)造函數(shù)里,用戶可以定義對象的拷貝行為是深拷貝還是淺拷貝,如果用戶沒有實現(xiàn)自己的拷貝構(gòu)造函數(shù),那么編譯器會提供一個默認實 現(xiàn),該實現(xiàn)使用的是按位拷貝(bitwise copy),也即本文所說的淺拷貝。構(gòu)造函數(shù)何時被調(diào)用呢?通常以下三種情況需要拷貝對象,此時拷貝構(gòu)造函數(shù)將會被調(diào)用。        1.一個對象以值傳遞的方式傳入函數(shù)體        2.一個對象以值傳遞的方式從函數(shù)返回        3.一個對象需要通過另外一個對象進行初始化4.C# MemberwiseClone與ICloneable接口        和C++里的拷貝構(gòu)造函數(shù)一樣,C#也為每個對象提供了淺拷貝的默認實現(xiàn),不過C#里沒有拷貝構(gòu)造函數(shù),而是通過頂級類型Object里的 MemberwiseClone方法。MemberwiseClone 方法創(chuàng)建一個淺表副本,方法是創(chuàng)建一個新對象,然后將當前對象的非靜態(tài)字段復制到該新對象。有沒有默認的深拷貝實現(xiàn)呢?當然是沒有,因為需要所有參與拷貝 的對象定義自己的深拷貝行為。C++里需要用戶實現(xiàn)拷貝構(gòu)造函數(shù),重寫默認的淺拷貝;C#則不同,C#(確切的說是.NET Framework,而非C#語言)提供了               ICloneable 接口,包含一個成員 Clone,它用于支持除 MemberwiseClone 所提供的克隆之外的克隆。C++通過拷貝構(gòu)造函數(shù)無法確定子對象實現(xiàn)的是深拷貝還是淺拷貝,而C#在“強制”實現(xiàn)淺拷貝的基礎上,提供 ICloneable 接口由用戶定義深拷貝行為,通過接口來強制約束所有參與拷貝的對象,個人覺得,這也算是一小點C#對C++的改進。 5.深拷貝策略與實現(xiàn)        深拷貝的要點就是確保所有參與拷貝的對象都要提供自己的深拷貝實現(xiàn),不管是C++拷貝構(gòu)造函數(shù)還是C#的ICloneable 接口,事實上都是一種拷貝的約定。有了事先的約定,才能約束實現(xiàn)上的統(tǒng)一,所以關鍵在于設計。        但偶爾也會在后期才想到要深拷貝,怎么辦?總不能修改所有之前的實現(xiàn)吧。有沒有辦法能夠通過頂級類而不關心內(nèi)部的子對象直接進行深拷貝呢?能不 能搞個萬能的深拷貝方法,在想用的時候立即用,而不考慮前期的設計。這樣“大包大攬”的方法,難點在于實現(xiàn)時必須自動獲取子對象的信息,分別為子對象實現(xiàn) 深拷貝。C++里比較困難,.NET的反射機制使得實現(xiàn)容易一些。不過這樣的方法雖然通用,實則破壞了封裝,也不符合“每個類對自己負責”的設計原則。        基于.NET的反射機制,以前寫了一個通用的序列化方法,現(xiàn)在可以拿過來,先序列化,然后再反序列化回來,也即是一個深拷貝,示例代碼如下:深拷貝示例代碼:

#region ICloneable Members        /// <summary>        /// 此處的復制為深拷貝,在實現(xiàn)上,為了簡化,采用序列化和反序列化。        /// </summary>        /// <returns>深拷貝對象</returns>        public object Clone()        {            Student stu = new Student();            xmlStorageHelper helper = new XmlStorageHelper();            string strXml = helper.ConvertToString(this);            helper.LoadFromString(stu, strXml);   //從XML字符串來賦值            return stu;        }        #endregion


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 南开区| 富平县| 霸州市| 通河县| 霍邱县| 伊春市| 厦门市| 武陟县| 安国市| 济南市| 普安县| 安平县| 纳雍县| 兴仁县| 武义县| 临城县| 陈巴尔虎旗| 潢川县| 上饶县| 木兰县| 西吉县| 彭山县| 鄂托克前旗| 平度市| 宁陕县| 阳谷县| 海南省| 嘉义市| 清水河县| 宿松县| 永福县| 湖北省| 武宣县| 醴陵市| 龙南县| 搜索| 安国市| 达拉特旗| 南通市| 会理县| 汤原县|