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

首頁(yè) > 開發(fā) > 綜合 > 正文

關(guān)于Visual C#裝箱與拆箱的研究

2024-07-21 02:25:40
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
  • 網(wǎng)站運(yùn)營(yíng)seo文章大全
  • 提供全面的站長(zhǎng)運(yùn)營(yíng)經(jīng)驗(yàn)及seo技術(shù)!
  • 關(guān)于visual c#裝箱與拆箱的研究
    2004-09-15 作者: 出處: csdn

    在對(duì)這個(gè)問題展開討論之前,我們不妨先來(lái)問這么幾個(gè)問題,以系統(tǒng)的了解我們今天要探究的主題。

      觀者也許曾無(wú)數(shù)次的使用過諸如system.console類或.net類庫(kù)中那些品種繁多的類。那么,我想問的是它們究竟源自何處?c#又是如何聯(lián)系它們?有沒有支持我們個(gè)性化擴(kuò)展的機(jī)制或類型系統(tǒng)?又有哪些類型系統(tǒng)可供我們使用呢?如果我們這些pl們連這些問題都不知其然,更不知其所以然的話,c#之門恐怕會(huì)把我們拒之門外的。
    那就讓我們先停停手中的活兒,理理頭緒,對(duì)作為.net重要技術(shù)和基礎(chǔ)之一的cts(common type system)做一個(gè)饒有興趣的研究。顧名思義,cts就是為了實(shí)現(xiàn)在應(yīng)用程序聲明和使用這些類型時(shí)必須遵循的規(guī)則而存在的通用類型系統(tǒng)。在這要插一句,雖然也許大家都對(duì)此再熟悉不過了,但是我還是要強(qiáng)調(diào),.net將整個(gè)系統(tǒng)的類型分成兩大類 —— 值類型 和 引用類型。到此,你也許會(huì)怒斥:說了這么半天,你似乎還沒有切入正題呢!別慌!知道了.net類型系統(tǒng)的的特點(diǎn)并不代表你真正理解了這個(gè)類型系統(tǒng)的原理和存在的意義。
    大多數(shù)面向?qū)ο蟮恼Z(yǔ)言都有兩種類型:原類型(語(yǔ)言固有的類型,如整數(shù)、枚舉)和類。雖然在實(shí)現(xiàn)模塊化和實(shí)體化方面,面向?qū)ο蠹夹g(shù)體現(xiàn)了很強(qiáng)的能力,但是也存在一些問題,比如現(xiàn)在提到的這個(gè)系統(tǒng)類型問題,歷史告訴我們兩組類型造成了許多問題。首先就是兼容性問題,這個(gè)也是microsoft使勁抨擊的一點(diǎn),多數(shù)的oo語(yǔ)言存在這個(gè)弱點(diǎn),原因就是因?yàn)樗麄兊脑愋蜎]有共同的基點(diǎn),于是他們?cè)诒举|(zhì)上并不是真正的對(duì)象,它們并不是從一個(gè)通用基類里派生來(lái)的。怪不得,anders heijlsberg 笑稱其為“魔術(shù)類型”。

      正是由于這一缺陷,當(dāng)我們希望指定一個(gè)可以接受本語(yǔ)言支持的任何類型的參數(shù)的method時(shí),同樣的問題再次襲擾我們的大腦——不兼容。當(dāng)然,對(duì)于c++的pl大拿,也許這個(gè)沒有什么大不了的,他們會(huì)自豪的說,只要用重載的構(gòu)造器為每一種原類型編寫一個(gè)wrapper class 不就完了嘛!好吧,這樣總算是能共存了,但是,接下來(lái)我們?cè)趺磸倪@個(gè)魔術(shù)中得到我們最關(guān)心的東東 —— 結(jié)果呢?于是,他們依然會(huì)自信的打開boarland,熟練的編寫一個(gè)重載過的函數(shù)來(lái)從剛才的那個(gè) wrapper class 中獲取結(jié)果。兄弟 or 姐妹們 ,在當(dāng)時(shí)的歷史條件下,你們的行為是創(chuàng)舉,但是相對(duì)于現(xiàn)在,你將會(huì)為此付出代價(jià) —— 效率低下。畢竟,c++更依賴于對(duì)象,而非面向?qū)ο蟆3姓J(rèn)現(xiàn)實(shí)總比死要面子更理智一些!花這么大力氣,總算把鋪墊說完了,我想說的是:.net環(huán)境的cts 給我們帶來(lái)了方便。第一、cts中的所有東西都是對(duì)象;第二、所有的對(duì)象都源自一個(gè)基類——system.object類型。這就是所謂的單根層次結(jié)構(gòu)(singly rooted hierarchy)關(guān)于system.object的詳細(xì)資料請(qǐng)參考微軟的技術(shù)文檔。這里我們簡(jiǎn)略的談?wù)勆厦嫣岬竭^的兩大類型:value type 和 reference type。

      cts值類型的一個(gè)最大的特點(diǎn)是它們不能為null,言外之意就是值類型的變量總有一個(gè)值。在c#中,它包括有原類型、結(jié)構(gòu)、枚舉器。這里需要強(qiáng)調(diào)一點(diǎn):在傳遞值類型的變量時(shí),我們實(shí)際傳遞的是變量的值,而非底層對(duì)象的引用,這一點(diǎn)和傳遞引用類型的變量的情況截然不同;cts引用類型就好像是類型安全的指針,它可以為null。它包括 如類、接口、委托、數(shù)組等類型。對(duì)比前面值類型的特點(diǎn),當(dāng)我們分配一個(gè)引用類型時(shí),系統(tǒng)會(huì)在后臺(tái)的堆棧上分配一個(gè)值(內(nèi)存分配與位置)并返回對(duì)這個(gè)值的引用;當(dāng)值為null時(shí),說明沒有引用或類型指向某個(gè)對(duì)象。這就意味著,我們?cè)诼暶饕粋€(gè)引用類型的變量時(shí),被操作的是此變量的引用(地址),而不是數(shù)據(jù)。

      討論到這個(gè)地方的時(shí)候,本篇的主角終于閃亮登場(chǎng)了——欲吐血或者嘔吐的同志,請(qǐng)?jiān)偃棠鸵幌隆N蚁雴栆粋€(gè)問題先:在使用這種多類型系統(tǒng)時(shí)如何有效的拓展和提高系統(tǒng)的性能?也許就是在黑板上對(duì)這個(gè)問題的探討,西雅圖的那幫家伙們提出了box(裝箱) and unbox(拆箱) 的想法。簡(jiǎn)單的說。裝箱就是將值類型(value type)轉(zhuǎn)換為引用類型(reference type)的過程;反之,就是拆箱。(其實(shí)這種思想早八輩子就產(chǎn)生了)。下面我們就進(jìn)一步詳細(xì)的討論裝箱和拆箱的過程。在討論中,我們剛剛提到的問題的答案也就迎刃而解了。

    首先,我們先來(lái)看看裝箱過程,為此我們需要先做兩個(gè)工作:1、編寫例程; 2、打開ildasm(msil代碼察看工具)為此我們先來(lái)看看以下的代碼:

    using system;

    namespace structapp
    {
    ///
    /// boxandunbox 的摘要說明。
    ///
    public class boxandunbox
    {
    public boxandunbox()
    {
    //
    // todo: 在此處添加構(gòu)造函數(shù)邏輯
    //
    }
    /////////////////////////////////////////////////////////////////////////////////////
    static void main(string[] args)
    {
    double dubbox = 77.77; /// 定義一個(gè)值形變量
    object objbox = dubbox; /// 將變量的值裝箱到 一個(gè)引用型對(duì)象中
    console.writeline("the value is '{0}' and the boxed is {1}",dubbox,objbox.tostring());
    }
    /////////////////////////////////////////////////////////////////////////////////////
    }
    }

      代碼中,本篇我們只需要關(guān)注main()方法下加注釋的兩行代碼,第一行我們創(chuàng)建了一個(gè)double類型的變量(dubbox)。顯然按規(guī)則,cts規(guī)定double是原類型,所以dubbox自然就是值類型的變量;第二行其實(shí)作了三個(gè)工作,這個(gè)將在下面的msil代碼中看的一清二楚。第一步取出dubbox的值,第二步將值類型轉(zhuǎn)換引用類型,第三步傳值給objbox。

      msil代碼如下:

    .method private hidebysig static void main(string[] args) cil managed
    {
    .entrypoint
    // 代碼大小 40 (0x28)
    .maxstack 3
    .locals init ([0] float64 dubbox,
    [1] object objbox)
    il_0000: ldc.r8 77.769999999999996
    il_0009: stloc.0
    il_000a: ldloc.0
    il_000b: box [mscorlib]system.double
    il_0010: stloc.1
    il_0011: ldstr "the value is '{0}' and the boxed is {1}"
    il_0016: ldloc.0
    il_0017: box [mscorlib]system.double
    il_001c: ldloc.1
    il_001d: callvirt instance string [mscorlib]system.object::tostring()
    il_0022: call void [mscorlib]system.console::writeline(string,
    object,
    object)
    il_0027: ret
    } // end of method boxandunbox::main

      在msil中,第il_0000 至 il_0010 行是描述前面兩行代碼的。參照c#的msil手冊(cè),觀者不難理解這段底層代碼的執(zhí)行過程,在這我著重描述一下當(dāng)dubbox被裝箱時(shí)所發(fā)生的故事:(1)劃分堆棧內(nèi)存,在堆棧上分配的內(nèi)存 = dubbox的大小 + objbox及其結(jié)構(gòu)所占用的空間;(2)dubbox的值(77.7699999999996)被復(fù)制到新近分配的堆棧中;(3)將分配給objbox的地址壓棧,此時(shí)它指向一個(gè)object類型,即引用類型。

      拆箱作為裝箱的逆過程,看上去好像很簡(jiǎn)單,其實(shí)里面多了很多值的思考的東西。首先,box的時(shí)候,我們不需要顯式的類型轉(zhuǎn)換,但是在unbox時(shí)就必須進(jìn)行類型轉(zhuǎn)換。這是因?yàn)橐妙愋偷膶?duì)象可以被轉(zhuǎn)換為任何類型。(當(dāng)然,這也是電腦和人腦一個(gè)差別的體現(xiàn))類型轉(zhuǎn)換不容回避的將會(huì)受到來(lái)自cts管理中心的監(jiān)控——其標(biāo)準(zhǔn)自然是依據(jù)規(guī)則。(其內(nèi)容的容量足以專門設(shè)一章來(lái)討論)好了,我們還是先來(lái)看看下面這段代碼吧:

    using system;

    namespace structapp
    {
    ///
    /// boxandunbox 的摘要說明。
    ///
    public class boxandunbox
    {
    public boxandunbox()
    {
    //
    // todo: 在此處添加構(gòu)造函數(shù)邏輯
    //
    }
    /////////////////////////////////////////////////////////////////////////////////////
    static void main(string[] args)
    {
    double dubbox = 77.77;
    object objbox = dubbox;
    double dubunbox = (double)objbox; /// 將引用型對(duì)象拆箱 ,并返回值
    console.writeline("the value is '{0}' and the unboxed is {1}",dubbox,dubunbox);
    }
    /////////////////////////////////////////////////////////////////////////////////////
    }
    }

      與前面裝箱的代碼相比,本段代碼多加了一行double dubunbox = (double)objbox;新加的這行代碼作了四個(gè)工作,這個(gè)也將體現(xiàn)在msil代碼中。第一步將一個(gè)值壓入堆棧;第二步將引用類型轉(zhuǎn)換為值類型;第三步間接將值壓棧;第四步傳值給dubunbox。

      msil代碼如下:

    .method private hidebysig static void main(string[] args) cil managed
    {
    .entrypoint
    // 代碼大小 48 (0x30)
    .maxstack 3
    .locals init ([0] float64 dubbox,
    [1] object objbox,
    [2] float64 dubunbox)
    il_0000: ldc.r8 77.769999999999996
    il_0009: stloc.0
    il_000a: ldloc.0
    il_000b: box [mscorlib]system.double
    il_0010: stloc.1
    il_0011: ldloc.1
    il_0012: unbox [mscorlib]system.double
    il_0017: ldind.r8
    il_0018: stloc.2
    il_0019: ldstr "the value is '{0}' and the unboxed is {1}"
    il_001e: ldloc.0
    il_001f: box [mscorlib]system.double
    il_0024: ldloc.2
    il_0025: box [mscorlib]system.double
    il_002a: call void [mscorlib]system.console::writeline(string,
    object,
    object)
    il_002f: ret
    } // end of method boxandunbox::main

      在msil中,第il_0011 至 il_0018 行是描述新行代碼的。參照c#的msil手冊(cè),觀者不難理解這段底層代碼的執(zhí)行過程,在此我著重描述一下objbox在拆箱時(shí)的遭遇:(1)環(huán)境須先判斷堆棧上指向合法對(duì)象的地址,以及在對(duì)此對(duì)象向指定的類型進(jìn)行轉(zhuǎn)換時(shí)是否合法,如果不合法,就拋出異常;(2)當(dāng)判斷類型轉(zhuǎn)換正確,就返回一個(gè)指向?qū)ο髢?nèi)的值的指針。

      看來(lái),裝箱和拆箱也不過如此,費(fèi)了半天勁,剛把‘值’給裝到‘箱’里去了,有費(fèi)了更多的勁把它拆解了,郁悶啊!細(xì)心的觀者,可能還能結(jié)合代碼和msil看出,怎么在調(diào)用console.writeline()的過程中又出現(xiàn)了兩次box,是的,我本想偷懶逃過這節(jié),但是既然已被發(fā)現(xiàn),就應(yīng)該大膽的面對(duì),其實(shí)這就是傳說中的“暗箱操作”啊! 因?yàn)閏onsole.writeline方法有許多的重載版本,此處的版本是以兩個(gè)string對(duì)象為參數(shù),而具有object 類型的參數(shù)的重載是編譯器找到的最接近的版本,所以,編譯器為了求得與這個(gè)方法的原型一致,就必須對(duì)值類型的dubbox和dubunbox分別進(jìn)行裝箱(轉(zhuǎn)換成引用類型)。

      所以,為了避免由于無(wú)謂的隱式裝箱所造成的性能損失,在執(zhí)行這些多類型重載方法之前,最好先對(duì)值進(jìn)行裝箱。現(xiàn)在我們把上述地代碼改進(jìn)為:

    using system;

    namespace structapp
    {
    ///
    /// boxandunbox 的摘要說明。
    ///
    public class boxandunbox
    {
    public boxandunbox()
    {
    //
    // todo: 在此處添加構(gòu)造函數(shù)邏輯
    //
    }
    ///////////////////////////////////////////////////////////////////
    static void main(string[] args)
    {
    double dubbox = 77.77;
    object objbox = dubbox;
    double dubunbox = (double)objbox;
    object objunbox = dubunbox;
    console.writeline("the value is '{0}' and the unboxed is {1}",objbox,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 objunbox)
    il_0000: ldc.r8 77.769999999999996
    il_0009: stloc.0
    il_000a: ldloc.0
    il_000b: box [mscorlib]system.double
    il_0010: stloc.1
    il_0011: ldloc.1
    il_0012: unbox [mscorlib]system.double
    il_0017: ldind.r8
    il_0018: stloc.2
    il_0019: ldloc.2
    il_001a: box [mscorlib]system.double
    il_001f: stloc.3
    il_0020: ldstr "the value is '{0}' and the unboxed is {1}"
    il_0025: ldloc.1
    il_0026: ldloc.3
    il_0027: call void [mscorlib]system.console::writeline(string,
    object,
    object)
    il_002c: ret
    } // end of method boxandunbox::main

      我暈!這算嘛事兒呀!看完后是不是該吐血的吐血,該上吊的上吊呀!相信能堅(jiān)持到看完最后一個(gè) "!" 的同志一定是個(gè)好同志。

      其實(shí),我們也可以妄加揣測(cè)一下:引用型應(yīng)當(dāng)屬于高級(jí)類型,而值型屬于原始類型,箱只是一個(gè)概念、一個(gè)秩序、一套規(guī)則或準(zhǔn)確說是一個(gè)邏輯。原始的東西作為基礎(chǔ),其復(fù)雜性和邏輯性不會(huì)很高,而高級(jí)的東西就不那么穩(wěn)定了,它會(huì)不斷的進(jìn)化和發(fā)展,因?yàn)檫@個(gè)邏輯的‘箱’會(huì)不斷地被要求擴(kuò)充和完善。由此思路推演,我們就不難預(yù)測(cè)出未來(lái)我們需要努力的方向和成功機(jī)會(huì)可能存在的地方—— !


    發(fā)表評(píng)論 共有條評(píng)論
    用戶名: 密碼:
    驗(yàn)證碼: 匿名發(fā)表
    主站蜘蛛池模板: 通化县| 府谷县| 东丰县| 阳城县| 昌都县| 巴塘县| 五大连池市| 布尔津县| 尼玛县| 凤城市| 措美县| 东乡族自治县| 谷城县| 兴宁市| 腾冲县| 错那县| 奉新县| 阿荣旗| 侯马市| 卓尼县| 浏阳市| 巴林右旗| 林周县| 西昌市| 文安县| 红原县| 隆林| 黄冈市| 荥阳市| 惠来县| 芮城县| 壶关县| 上蔡县| 吉安市| 上饶市| 离岛区| 平罗县| 克东县| 剑阁县| 内丘县| 鹤山市|