1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        面試官:C#中的 as 和 is的區(qū)別?

        共 4310字,需瀏覽 9分鐘

         ·

        2021-02-26 21:50


        ?

        本文是《編寫高質(zhì)量代碼改善C#程序的157個建議》第一章基本語言要素之建議3區(qū)別對待強制類型轉(zhuǎn)換與as和is,喜歡本書請到各大商城購買原書,支持正版。

        在闡述本建議之前,首先需要明確什么是強制類型轉(zhuǎn)換,以及強制類型轉(zhuǎn)換意味著什么。從語法結(jié)構(gòu)上來看,類似下面的代碼就是強制類型轉(zhuǎn)換。

        secondType = (SecondType)firstType;

        但是,強制類型轉(zhuǎn)換可能意味著兩件不同的事情:

        • FirstType和SecondType彼此依靠轉(zhuǎn)換操作符來完成兩個類型之間的類型轉(zhuǎn)換。
        • FirstType是SecondType的基類。

        類型之間如果存在強制類型轉(zhuǎn)換,那么它們之間的關(guān)系,要么是第一種,要么是第二種,不能同時既是繼承的關(guān)系,又提供了類型轉(zhuǎn)換符。

        首先看第一種情況,當FirstType和SecondType存在轉(zhuǎn)換操作符時的代碼如下:

        class FirstType
        {
          public string Name { getset; }
        }

        class SecondType
        {
          public string Name { getset; }
          public static explicit operator SecondType(FirstType firstType)
          {
            SecondType secondType = new SecondType() { Name = $"類型轉(zhuǎn)換自:{firstType.Name}" };

            return secondType;
          }
        }

        在這種情況下,如果想類型轉(zhuǎn)換成功則必須使用強制類型轉(zhuǎn)換,而不是使用as操作符。

        FirstType firstType = new FirstType { Name="First Type"};
        SecondType secondType = (SecondType)firstType;    // 類型轉(zhuǎn)換成功
        // secondType = firstType as SecondType;     // 編譯期類型轉(zhuǎn)換失敗,編譯通不過

        不過,這里需要討論的不是像以上代碼這樣的簡單應用,而是稍微復雜一點的應用。為了滿足更進一步的需求,我們需要寫一個通用的方法,需要對FirstType或者SecondType做一些處理,方法看起來應該像下面這樣:

        static void DoWithSomeType(object obj)
        {
          SecondType secondType = (SecondType)obj;
        }
        ?

        注意 是否對這種方法聲明方式有一點熟悉?事實上,如果再加一個參數(shù)EventArgs,上面的方法就可以注冊成為一個典型的CLR事件方法了。

        如果運行本段代碼,會帶來一個問題:若在調(diào)用方法的時候,傳入的參數(shù)是一個FirstType對象,那就會引發(fā)異常。你可能會問,在上一段代碼中,有這樣的寫法:

        FirstType firstType = new FirstType() { Name = "First Type" };
        SecondType secondType = (SecondType)firstType;

        而DoWithSomeType方法提供的代碼,看起來無非像下面這樣:

        FirstType firstType = new FirstType() { Name = "First Type" };
        object obj = firstType;
        SecondType secondType = (SecondType) obj;

        也就是說,這段代碼和上段代碼相比,僅僅多了一層類型轉(zhuǎn)換,實際上obj還是firstType,為什么類型轉(zhuǎn)換就失敗了呢?這是因為編譯器還不夠聰明,或者說我們欺騙了編譯器。針對(SecondType)obj,編譯器首先判斷的是:SecondType和object之間有沒有繼承關(guān)系。因為在C#中,所有的類型繼承自object的,所以上面的代碼編譯起來肯定沒有問題。但是編譯器會自動產(chǎn)生代碼來檢查obj在運行時是不是SecondType,這樣就繞過了類型轉(zhuǎn)換操作符,所以會轉(zhuǎn)換失敗。因此,這里的建議是:

        如果類型之間都上溯到了某個共同的基類,那么根據(jù)此基類進行的類型轉(zhuǎn)換(即基類類型轉(zhuǎn)換為子類本身)應該使用as。子類與子類之間的類型轉(zhuǎn)換,則應該提供類型轉(zhuǎn)換操作符,以便進行強制類型轉(zhuǎn)換。

        ?

        注意 再次強調(diào),類型轉(zhuǎn)換操作符實際上就是一個方法,類型的轉(zhuǎn)換需要手工寫代碼完成。

        為了編寫更健壯的DoWithSomeType方法,應該按如下方式改造它:

        static void DoWithSomeType(object obj)
        {
          SecondType secondType = obj as SecondType;
          if (secondType != null)
          {
            // 省略
          }
        }

        as操作符永遠不會拋出異常,如果類型不匹配(被轉(zhuǎn)換對象的運行時類型即不是所轉(zhuǎn)換的目標類型,也不是其派生類型),或者類型轉(zhuǎn)換的源對象為null,那么類型轉(zhuǎn)換之后的值也為null。改造前的DoWithSomeType方法會因為引發(fā)異常帶來效率問題,而使用as后,就可以完美地避免這種問題。

        現(xiàn)在,再來看第二種情況,即FirstType是SecondType的基類。在這種情況下,即可以使用強制類型轉(zhuǎn)換,也可以使用as操作符,代碼如下所示:

        class Program
        {
          static void Main(string[] args)
          {
            SecondType secondType = new SecondType() { Name = "Second Type" };
            FirstType firstType1 = (FirstType)secondType;
            FirstType firstType2 = secondType as FirstType;
          }
        }

        class FirstType
        {
          public string Name { getset; }
        }

        class SecondType : FirstType
        {
        }

        但是,即使可以使用強制類型轉(zhuǎn)換,從效率的角度來看,也建議大家使用as操作符。

        知道了強制類型轉(zhuǎn)換和as之間的區(qū)別,我們再來看一下is操作符。DoWithSomeType的另一個版本,可以這樣來實現(xiàn),代碼如下所示:

        static void DoWithSomeType(object obj)
        {
          if (obj is SecondType)
          {
            SecondType secondType = obj as SecondType;
            // 省略
          }
        }

        這個版本顯然沒有上一個版本的效率高,因為當前這個版本進行了兩次類型檢測。但是,as操作符有一個問題,即它不能操作基元類型。如果涉及基元類型的算法,就需要通過is類型轉(zhuǎn)換前的類型來進行判斷,以免類型轉(zhuǎn)換失敗。







        回復 【關(guān)閉】關(guān)
        回復 【實戰(zhàn)】獲取20套實戰(zhàn)源碼
        回復 【被刪】
        回復 【訪客】
        回復 【小程序】學獲取15套【入門+實戰(zhàn)+賺錢】小程序源碼
        回復 【python】學微獲取全套0基礎(chǔ)Python知識手冊
        回復 【2019】獲取2019 .NET 開發(fā)者峰會資料PPT
        回復 【加群】加入dotnet微信交流群

        @程序員,這筆錢下個月可以領(lǐng)!


        臥槽:微信可以這樣換個字體了!



        瀏覽 35
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            一级做a爰片久久毛片潮喷 | 欧美成熟熟女在线观看视频 | 91久久国语露脸精品国产高跟 | 日本视频二区 | 五月天成人社区 | 偷拍视频图片综合网 | 舔花核视频 | 国内久久成人网站地址 | 中文字幕日本伦理电影 | 91狠狠综合 |