學過編程的朋友都知道類型轉換,並且也都清楚“隱式轉換”、“顯式轉換”、“裝箱”、“拆箱”等概念。但是,類型轉換究竟有多少種?如何對其進行劃分?何時應該使用何種類型轉換?
1.1、相關概念
類型轉換髮生的時機 (Occasion)——當發生值的複製時,可能會發生類型轉換。
所謂“值的複製”,包括賦值運算和方法傳參。如果被賦值的變數或方法的形式參數的類型與實際的物件類型不同,就需要進行類型轉換。
1.2、類型轉換的分類
C#中的類型轉換有兩種分類方法:
一種是根據轉換方式的不同進行劃分,可以分為顯式 (Explicit)
轉換和隱式 (Implicit) 轉換兩種;
另外一種是根據源類型和目標類型之間的關係進行劃分,可以分為變換 (Conversion)、投射
(Cast)和裝箱/拆箱 (Boxing/Unboxing)。
下面這張圖描繪了各種類型轉化,以及它們發生的時機。
2.1 顯式轉換和隱式轉換
從直觀上看,顯式和隱式轉換隻是文法上面的差別。當發生類型轉換時,如果在代碼中明確指定了目標類型,則稱為顯式轉換,否則則稱為隱式轉換。
下面的代碼介紹了在C#語言中進行顯式和隱式轉換時的文法。int x = 10;
long y = x; // 隱式轉換
x = (int) y; // 顯示轉換
x=Convert.ToInt32(y);// 顯示轉換
需要注意的是,不是任意兩種類型之間都能隨意進行轉換的。如bool和string沒有隱式轉換。
隱式轉換規則:任何類型A,只要取值範圍完全包含在類型B的取值範圍之內,就可以隱式轉換為類型B。
另外,無論顯式轉換還是隱式轉換,都可能會失敗。如果顯式轉換失敗,會在運行時拋出異常(這個異常可能是InvalidCastException,也可能是
InvalidOperationException、OverflowException等具體異常);如果隱式轉換失敗,則會在編譯時間得到一個錯誤,
指出不能進行隱式轉換。
最後,隱式轉換也可以用顯式轉換替代,但顯式轉換不能用隱式轉換替代。換句話說,可以用顯式轉換的地方,用隱式轉換也沒什麼問題;但需要顯式轉換的地方,就一定不能用隱式轉換。
下面將從另外一種角度介紹各種不同的類型轉換。
2.2 變換、投射、裝箱/拆箱
根據參與類型轉換的兩種類型(源類型和目標類型)的關係不同,可以將類型轉換分成三種;即:
如果源類型和目標類型一個是實值型別一個是參考型別,則稱為裝箱/拆箱;
如果源類型和目標類型之間存在著直接或間接繼承,則稱為投射;
如果源類型和目標類型不具備上述兩種關係,如兩種簡單實值型別或兄弟/鄰居類型(有著共同的祖先類)之間,則稱為普通類型轉換(或稱“變換”)。
變換
變換是最普通的一種類型轉換,通常發生在:
簡單(內建)實值型別之間;
重載了類型轉換運算子的類型之間;
簡
單實值型別就是int、long、float、double等類型。在這些類型之間轉換的時候,如果不會發生精度損失,則可以使用隱式轉換,否則必須使用顯
式轉換。換言之,從較短的類型向較長的類型轉換,可以用隱式轉換;從較長的向較短的轉換,必須用顯式轉換(“長短”指的是:int長4位元組,long長8
位元組,所以int比long短。)
投射
當源類型和目標類型具有直接或間接的繼承關係時,發生的類型轉換屬於投射。如果將子類型的一個對象轉換成祖先類型,則稱向上投射 (Upcast)。反之,將祖先類型的對象轉換為子孫類型,則稱向下投射 (Downcast)。
中,CA到CB、CA到CC、CA到CD、CB到CC的轉換屬於向下投射,而CB到CA、CC到CA、CD到CA、CC到CB的轉換屬於向上投射。
向
上投射可以使用隱式轉換,但向下投射必須使用顯示轉換。這是因為當發生繼承關係時,子類將具有父類所有的成員(儘管父類中的private成員在子類中無
法訪問,但子類確實擁有這些成員),因此子類對象向父類轉換時可以確保不會丟失成員,而如果父類對象向子類轉換,不一定保證對象具備子類特有的成員。
需要注意的是,如果兩個類型位於同一繼承樹中,但沒有直接或間接繼承關係(通常稱這樣的類型為“兄弟類型”或“鄰居類型”,如中的CB和CD、CC和CD),是不允許發生任何轉換的,除非重載了類型轉換運算子。
下面解釋一下為什麼將這種類型的轉換稱為投射。
假設類CA中定義了一個屬性、一個事件和一個方法,現在用方塊表示屬性、用三角表示事件、用圓圈表示方法,則可以將CA繪製為下面的圖形。
假設類CB繼承自CA,並定義了額外的一個屬性和一個方法,則可以將CB繪製為下面的圖形。
現在考慮用一個和CA形狀一致的模板罩在CB類型的一個對象上,並透過模板去看這個對象(如所示),則可以看到對象的一個視圖,並且從其中只能看到CA類中定義的成員。
這個情形符合這種轉換。如果將視線想象成光線,則形成了一個光線的投射。
裝箱/拆箱
當發生類型轉換時,如果源類型和目標類型一個是實值型別而另一個是參考型別時,將發生裝箱/拆箱轉換。
從實值型別向參考型別的轉換稱為裝箱,而從參考型別向實值型別轉換稱為拆箱。
裝箱時,會在堆中建立一個新的對象(作為一個“箱子”),並將實值型別值複製到這個對象中(把這個值“裝起來”);而拆箱時,只需將對象中的值複製到棧上。
在裝箱/拆箱中,何時使用顯式(隱式)轉換是不確定的,取決於類型中重載了哪種轉換運算子。
轉自:http://developer.51cto.com/art/200612/36339.htm