天天看點

多用as少用強制類型轉換

在 C# 中存在一個名叫靜态類型檢查的機制,這個機制可以讓編譯器幫助我們把類型不服的用法找出來,進而使得應用程式在運作期間加少一些類型檢查的操作。但是有時候我們還是需要進行運作期類型檢查,比如我們在設計架構時将方法的參數類型定義為 object ,那麼這時我們就有很大的可能需要将 object 類型的參數先轉換為其他類型。我們進行轉換時會有兩種方法可以使用:一種是強制類型轉換,這種方法可以繞過編譯器的類型檢查,另一種是先通過 is 判斷操作是否合理,是否可以轉換,然後再使用 as 運算符進行轉換,或者使用強制類型轉換。下面我們就來講解一下為什麼多使用 as 少使用強制類型轉換。

零、as and is

使用 as 進行類型轉換會比強制類型轉換更加安全,而且運作時效率更高。但是這裡有一點需要注意的是 as 和 is 運算符不會考慮使用者所定義的類型轉換,隻有當運作期的類型與要轉換到的類型相符時才能順利進行。一般來說 as 類型轉換很少會出現為了類型轉換而建立新的對象,隻有在 as 運算符把裝箱值類型轉換未裝箱且可以為 null 的類型時才會建立新對象。

is 運算符遵循多态原則,也就是說例如 變量 Husky(哈士奇)是 Dog 類型,并且 Dog 類型繼承自 Animal 類型,那麼 代碼段

husky is Animal

傳回值就是 True 。是以我們可以利用這一特性來判斷某個對象是否是某個具體類型。當然我們也可用通過 GetType 方法來查詢對象的運作期類型,這樣可以使開發人員寫出比 as 和 is 更加具體更加詳細的類型,這主要歸功于它所傳回的對象類型能夠和某種特定類型進行對比。

一、為什麼不用強制類型轉換

我們先來看一段代碼:

try
{
    object obj = Factory.GetObject();
    Animal animal;
    animal = (Animal) obj;
    if (animal !=null)
    {
        // more code
    }
    // more code
}
catch (InvalidCastExcept ex)
{
    // more code
}
           

在上述代碼中我們使用了強制類型轉換将 object 類型的變量轉換為 Animal 類型,我相信部分開發人員在實際開發中都會這麼寫,這麼些也不為過,但是這其中存在一個問題,開發人員需要處理兩個問題。首先程式如果無法将變量 obj 轉換為 Animal 類型将抛出 InvalidCastException 異常,是以我們必須捕獲,其次在強制類型轉換時遇到 null 的時候并不會抛出異常,是以我們還要判斷變量 animal 是否為 null 。既然強制類型轉換有這個問題,那我們該如何解決呢?這時我們就可以用到 as 和 is 運算符了,同樣我們先看一下代碼:

try
{
    object obj = Factory.GetObject();
    if (obj is Animal)
    {
        Animal animal =  obj as Animal;
        // more code
    }
    else
    {
        // more code
    }
}
           

利用這種方法我們首先判斷 obj 是否可以轉換為 Animal 類型,如果可以就利用 as 運算符來轉換,反之執行其他代碼。既不需要捕獲錯誤,也不需要強制轉換,減少了代碼量同時也減少了代碼出錯的機率。

as 運算符和強制類型轉之間有一個很大的差別,那就是如何對待使用者自定義的轉換邏輯。 as 和 is 運算符除了必須進行的裝箱和拆箱外,它不會執行其他任何操作,也就是說 as 和 is 隻會判斷帶轉換對象在運作期是什麼類型,并根據結果進行相應的處理。那麼如果帶轉換對象既不屬于目标類型也不屬于目标類型所派生出來的類型的話, as 操作就宣告失敗。強制類型轉換則不然,它有可能使用一些類型的轉換邏輯進行類型轉換,而且不僅僅是使用者自定義的轉換邏輯,還包含了内置類型之間的轉換。但是要注意的是強制類型轉換可以會造成資訊丢失,例如從 long 強制轉換為 short 。

在某些情況下利用強制類型轉換從代碼上來看似乎可以轉換成功,但實際上卻轉換不成功。這時為什麼呢?雖然強制類型轉換會把使用者自定義的轉換邏輯考慮進去,但是它隻針對對象的編譯期類型,編譯期類型并不是是基類型。例如帶轉換類型在編譯期是 object 類型,是以編譯器會将它看作 object ,這時如果進行強制類型轉換的話就會報錯。

前面說了那麼多使用 as 的好處,那麼在這一小節裡我們就來說說在什麼時候不能使用 as 和 is 。同樣,先來看一小段代碼:

object obj =Factory.GetValue();
int num = obj as int;
           

上面的這段代碼運作起來後将會報錯,為什麼呢?這是因為當 obj 不是 int 類型時傳回的值是 null ,但是 int 類型無法接受 null 值。是以當指定類型不可接受 null 值時 as 無法進行類型轉換。

二、一個問題

三、總結