關(guān)于Visual C#裝箱與拆箱的研究_第1頁
關(guān)于Visual C#裝箱與拆箱的研究_第2頁
關(guān)于Visual C#裝箱與拆箱的研究_第3頁
關(guān)于Visual C#裝箱與拆箱的研究_第4頁
關(guān)于Visual C#裝箱與拆箱的研究_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、關(guān)于Visual C#裝箱與拆箱的研究在對這個問題展開討論之前,我們不妨先來問這么幾個問題,以系統(tǒng)的了解我們今天要探究的主題。觀者也許曾無數(shù)次的使用過諸如System.Console類或.NET類庫中那些品種繁多的類。那么,我想問的是它們究竟源自何處?C#又是如何聯(lián)系它們?有沒有支持我們個性化擴(kuò)展的機(jī)制或類型系統(tǒng)?又有哪些類型系統(tǒng)可供我們使用呢?如果我們這些PL們連這些問題都不知其然,更不知其所以然的話,C#之門恐怕會把我們拒之門外的。那就讓我們先停停手中的活兒,理理頭緒,對作為.NET重要技術(shù)和基礎(chǔ)之一的CTS(Common Type System做一個饒有興趣的研究。顧名思義,CTS就是為

2、了實(shí)現(xiàn)在應(yīng)用程序聲明和使用這些類型時必須遵循的規(guī)則而存在的通用類型系統(tǒng)。在這要插一句,雖然也許大家都對此再熟悉不過了,但是我還是要強(qiáng)調(diào),.Net將整個系統(tǒng)的類型分成兩大類 值類型 和 引用類型。到此,你也許會怒斥:說了這么半天,你似乎還沒有切入正題呢!別慌!知道了.Net類型系統(tǒng)的的特點(diǎn)并不代表你真正理解了這個類型系統(tǒng)的原理和存在的意義。大多數(shù)面向?qū)ο蟮恼Z言都有兩種類型:原類型(語言固有的類型,如整數(shù)、枚舉)和類。雖然在實(shí)現(xiàn)模塊化和實(shí)體化方面,面向?qū)ο蠹夹g(shù)體現(xiàn)了很強(qiáng)的能力,但是也存在一些問題,比如現(xiàn)在提到的這個系統(tǒng)類型問題,歷史告訴我們兩組類型造成了許多問題。首先就是兼容性問題,這個也是Mic

3、rosoft使勁抨擊的一點(diǎn),多數(shù)的OO語言存在這個弱點(diǎn),原因就是因?yàn)樗麄兊脑愋蜎]有共同的基點(diǎn),于是他們在本質(zhì)上并不是真正的對象,它們并不是從一個通用基類里派生來的。怪不得,Anders Heijlsberg 笑稱其為“魔術(shù)類型”。正是由于這一缺陷,當(dāng)我們希望指定一個可以接受本語言支持的任何類型的參數(shù)的Method時,同樣的問題再次襲擾我們的大腦不兼容。當(dāng)然,對于C+的PL大拿,也許這個沒有什么大不了的,他們會自豪的說,只要用重載的構(gòu)造器為每一種原類型編寫一個Wrapper Class 不就完了嘛!好吧,這樣總算是能共存了,但是,接下來我們怎么從這個魔術(shù)中得到我們最關(guān)心的東東 結(jié)果呢?于是,他

4、們依然會自信的打開Boarland,熟練的編寫一個重載過的函數(shù)來從剛才的那個 Wrapper Class 中獲取結(jié)果。兄弟 or 姐妹們 ,在當(dāng)時的歷史條件下,你們的行為是創(chuàng)舉,但是相對于現(xiàn)在,你將會為此付出代價 效率低下。畢竟,C+更依賴于對象,而非面向?qū)ο?。承認(rèn)現(xiàn)實(shí)總比死要面子更理智一些!花這么大力氣,總算把鋪墊說完了,我想說的是:.Net環(huán)境的CTS 給我們帶來了方便。第一、CTS中的所有東西都是對象;第二、所有的對象都源自一個基類System.Object類型。這就是所謂的單根層次結(jié)構(gòu)(singly rooted hierarchy)關(guān)于System.Object的詳細(xì)資料請參考微軟的

5、技術(shù)文檔。這里我們簡略的談?wù)勆厦嫣岬竭^的兩大類型:Value Type 和 Reference Type。CTS值類型的一個最大的特點(diǎn)是它們不能為null,言外之意就是值類型的變量總有一個值。在C#中,它包括有原類型、結(jié)構(gòu)、枚舉器。這里需要強(qiáng)調(diào)一點(diǎn):在傳遞值類型的變量時,我們實(shí)際傳遞的是變量的值,而非底層對象的引用,這一點(diǎn)和傳遞引用類型的變量的情況截然不同;CTS引用類型就好像是類型安全的指針,它可以為null。它包括 如類、接口、委托、數(shù)組等類型。對比前面值類型的特點(diǎn),當(dāng)我們分配一個引用類型時,系統(tǒng)會在后臺的堆棧上分配一個值(內(nèi)存分配與位置)并返回對這個值的引用;當(dāng)值為null時,說明沒有引

6、用或類型指向某個對象。這就意味著,我們在聲明一個引用類型的變量時,被操作的是此變量的引用(地址),而不是數(shù)據(jù)。 討論到這個地方的時候,本篇的主角終于閃亮登場了欲吐血或者嘔吐的同志,請再忍耐一下。我想問一個問題先:在使用這種多類型系統(tǒng)時如何有效的拓展和提高系統(tǒng)的性能?也許就是在黑板上對這個問題的探討,西雅圖的那幫家伙們提出了Box(裝箱) and UnBox(拆箱) 的想法。簡單的說。裝箱就是將值類型(value type轉(zhuǎn)換為引用類型(reference type的過程;反之,就是拆箱。(其實(shí)這種思想早八輩子就產(chǎn)生了)。下面我們就進(jìn)一步詳細(xì)的討論裝箱和拆箱的過程。在討論中,我們剛剛提到的問題的

7、答案也就迎刃而解了。首先,我們先來看看裝箱過程,為此我們需要先做兩個工作:1、編寫例程; 2、打開ILDASM(MSIL代碼察看工具)為此我們先來看看以下的代碼:using System;namespace StructApp/ / BoxAndUnBox 的摘要說明。/ public class BoxAndUnBoxpublic BoxAndUnBox( / TODO: 在此處添加構(gòu)造函數(shù)邏輯/ static void Main(string argsdouble dubBox = 77.77; / 定義一個值形變量 object objBox = dubBox; / 將變量的值裝箱到 一

8、個引用型對象中 Console.WriteLine("The Value is '0' and The Boxed is 1",dubBox,objBox.ToString(;/代碼中,本篇我們只需要關(guān)注Main(方法下加注釋的兩行代碼,第一行我們創(chuàng)建了一個double類型的變量(dubBox。顯然按規(guī)則,CTS規(guī)定double是原類型,所以dubBox自然就是值類型的變量;第二行其實(shí)作了三個工作,這個將在下面的MSIL代碼中看的一清二楚。第一步取出dubBox的值,第二步將值類型轉(zhuǎn)換引用類型,第三步傳值給objBox。MSIL代碼如下:.method pr

9、ivate hidebysig static void Main(string args cil managed.entrypoint/ 代碼大小 40 (0x28.maxstack 3.locals init (0 float64 dubBox,1 object objBoxIL_0000: ldc.r8 77.769999999999996IL_0009: stloc.0IL_000a: ldloc.0IL_000b: box mscorlibSystem.DoubleIL_0010: stloc.1IL_0011: ldstr "The Value is '0'

10、 and The Boxed is 1"IL_0016: ldloc.0IL_0017: box mscorlibSystem.DoubleIL_001c: ldloc.1IL_001d: callvirt instance string mscorlibSystem.Object:ToString(IL_0022: call void mscorlibSystem.Console:WriteLine(string,object,objectIL_0027: ret / end of method BoxAndUnBox:Main在MSIL中,第IL_0000 至 IL_0010 行

11、是描述前面兩行代碼的。參照C#的MSIL手冊,觀者不難理解這段底層代碼的執(zhí)行過程,在這我著重描述一下當(dāng)dubBox被裝箱時所發(fā)生的故事:(1劃分堆棧內(nèi)存,在堆棧上分配的內(nèi)存 = dubBox的大小 + objBox及其結(jié)構(gòu)所占用的空間;(2dubBox的值(77.7699999999996被復(fù)制到新近分配的堆棧中;(3將分配給objBox的地址壓棧,此時它指向一個object類型,即引用類型。拆箱作為裝箱的逆過程,看上去好像很簡單,其實(shí)里面多了很多值的思考的東西。首先,box的時候,我們不需要顯式的類型轉(zhuǎn)換,但是在unbox時就必須進(jìn)行類型轉(zhuǎn)換。這是因?yàn)橐妙愋偷膶ο罂梢员晦D(zhuǎn)換為任何類型。(當(dāng)

12、然,這也是電腦和人腦一個差別的體現(xiàn)類型轉(zhuǎn)換不容回避的將會受到來自CTS管理中心的監(jiān)控其標(biāo)準(zhǔn)自然是依據(jù)規(guī)則。(其內(nèi)容的容量足以專門設(shè)一章來討論好了,我們還是先來看看下面這段代碼吧:using System;namespace StructApp/ / BoxAndUnBox 的摘要說明。/ public class BoxAndUnBoxpublic BoxAndUnBox( / TODO: 在此處添加構(gòu)造函數(shù)邏輯/ /static void Main(string argsdouble dubBox = 77.77; object objBox = dubBox; double dubUnBo

13、x = (doubleobjBox; / 將引用型對象拆箱 ,并返回值Console.WriteLine("The Value is '0' and The UnBoxed is 1",dubBox,dubUnBox;/與前面裝箱的代碼相比,本段代碼多加了一行double dubUnBox = (doubleobjBox;新加的這行代碼作了四個工作,這個也將體現(xiàn)在MSIL代碼中。第一步將一個值壓入堆棧;第二步將引用類型轉(zhuǎn)換為值類型;第三步間接將值壓棧;第四步傳值給dubUnBox。MSIL代碼如下:.method private hidebysig stat

14、ic void Main(string args cil managed.entrypoint/ 代碼大小 48 (0x30.maxstack 3.locals init (0 float64 dubBox,1 object objBox,2 float64 dubUnBoxIL_0000: ldc.r8 77.769999999999996IL_0009: stloc.0IL_000a: ldloc.0IL_000b: box mscorlibSystem.DoubleIL_0010: stloc.1IL_0011: ldloc.1IL_0012: unbox mscorlibSystem.

15、DoubleIL_0017: ldind.r8IL_0018: stloc.2IL_0019: ldstr "The Value is '0' and The UnBoxed is 1"IL_001e: ldloc.0IL_001f: box mscorlibSystem.DoubleIL_0024: ldloc.2IL_0025: box mscorlibSystem.DoubleIL_002a: call void mscorlibSystem.Console:WriteLine(string,object,objectIL_002f: ret / en

16、d of method BoxAndUnBox:Main在MSIL中,第IL_0011 至 IL_0018 行是描述新行代碼的。參照C#的MSIL手冊,觀者不難理解這段底層代碼的執(zhí)行過程,在此我著重描述一下objBox在拆箱時的遭遇:(1環(huán)境須先判斷堆棧上指向合法對象的地址,以及在對此對象向指定的類型進(jìn)行轉(zhuǎn)換時是否合法,如果不合法,就拋出異常;(2當(dāng)判斷類型轉(zhuǎn)換正確,就返回一個指向?qū)ο髢?nèi)的值的指針??磥恚b箱和拆箱也不過如此,費(fèi)了半天勁,剛把值給裝到箱里去了,有費(fèi)了更多的勁把它拆解了,郁悶??!細(xì)心的觀者,可能還能結(jié)合代碼和MSIL看出,怎么在調(diào)用Console.WriteLine(的過程中又出

17、現(xiàn)了兩次box,是的,我本想偷懶逃過這節(jié),但是既然已被發(fā)現(xiàn),就應(yīng)該大膽的面對,其實(shí)這就是傳說中的“暗箱操作”??! 因?yàn)镃onsole.WriteLine方法有許多的重載版本,此處的版本是以兩個String對象為參數(shù),而具有object 類型的參數(shù)的重載是編譯器找到的最接近的版本,所以,編譯器為了求得與這個方法的原型一致,就必須對值類型的dubBox和dubUnBox分別進(jìn)行裝箱(轉(zhuǎn)換成引用類型。所以,為了避免由于無謂的隱式裝箱所造成的性能損失,在執(zhí)行這些多類型重載方法之前,最好先對值進(jìn)行裝箱?,F(xiàn)在我們把上述地代碼改進(jìn)為:using System;namespace StructApp/ / B

18、oxAndUnBox 的摘要說明。/ public class BoxAndUnBoxpublic BoxAndUnBox( / TODO: 在此處添加構(gòu)造函數(shù)邏輯/ /static void Main(string argsdouble dubBox = 77.77; object objBox = dubBox; double dubUnBox = (doubleobjBox; object objUnBox = dubUnBox;Console.WriteLine("The Value is '0' and The UnBoxed is 1",objB

19、ox,objUnBox;/MSIL代碼:.method private hidebysig static void Main(string args cil managed.entrypoint/ 代碼大小 45 (0x2d.maxstack 3.locals init (0 float64 dubBox,1 object objBox,2 float64 dubUnBox,3 object objUnBoxIL_0000: ldc.r8 77.769999999999996IL_0009: stloc.0IL_000a: ldloc.0IL_000b: box mscorlibSystem.Dou

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論