麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

淺析C#深拷貝與淺拷貝

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

定義代碼如下:

/// <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    {        //為了簡(jiǎn)化,使用public 字段        public string Name;        public int Age;        //自定義類(lèi)型,假設(shè)每個(gè)Student只擁有一個(gè)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測(cè)試代碼:

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 + "]"); //再次打印兩個(gè)對(duì)象以比較 Console.ReadLine();

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

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


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 日韩视频在线视频 | 午夜视频在线观看91 | 成人做爽爽爽爽免费国产软件 | a视频在线播放 | 中韩毛片 | 国产精品观看在线亚洲人成网 | 国产午夜精品久久久久久免费视 | 成人毛片100免费观看 | 日本高清在线播放 | 91成人在线网站 | 欧美一级视频网站 | 国产99久久精品一区二区 | 一级成人免费 | 99成人精品视频 | 二区三区四区 | 黄色网址在线免费 | 自拍偷拍999 | 羞羞视频免费视频欧美 | 成人黄视频在线观看 | 姑娘第四集免费看视频 | 女人a级毛片 | av电影在线观看免费 | 毛片在线免费 | 国产资源在线视频 | 国产一级爱c视频 | 久久国产亚洲视频 | sesee99| 法国极品成人h版 | 91精品国产99久久久久久 | 午夜伊人| 在线无码| 极色品影院 | 精品国产乱码久久久久久丨区2区 | 免费亚洲视频在线观看 | 亚洲片在线 | 国产1区视频 | 午夜视频在线免费观看 | 一区二区三区视频在线播放 | 毛片在线视频观看 | 久草热久草视频 | 黄网免费看 |