<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 4310字,需瀏覽 9分鐘

           ·

          2021-02-26 21:50


          ?

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

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

          secondType = (SecondType)firstType;

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

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

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

          首先看第一種情況,當(dāng)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)換成功則必須使用強(qiáng)制類型轉(zhuǎn)換,而不是使用as操作符。

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

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

          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ù)此基類進(jìn)行的類型轉(zhuǎn)換(即基類類型轉(zhuǎn)換為子類本身)應(yīng)該使用as。子類與子類之間的類型轉(zhuǎn)換,則應(yīng)該提供類型轉(zhuǎn)換操作符,以便進(jìn)行強(qiáng)制類型轉(zhuǎn)換。

          ?

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

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

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

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

          現(xiàn)在,再來看第二種情況,即FirstType是SecondType的基類。在這種情況下,即可以使用強(qiáng)制類型轉(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
          {
          }

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

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

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

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







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

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


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



          瀏覽 34
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久急费看黄A毛片 | 插进去综合网 | 国产蜜臀秘 入口 | 国产骚B| 免费视频三区 |