一 什麼是轉換 轉換是接受一個類型的值並使用它作為另一個類型的等價值的過程。 下列代碼演示了將1個short類型的值強制轉換成byte類型的值。 short var1 = 5; byte var2 = 10; var2 = (byte) var1; //強制轉換,將var1的值轉換成byte類型 二 ...
一 什麼是轉換
轉換是接受一個類型的值並使用它作為另一個類型的等價值的過程。
下列代碼演示了將1個short類型的值強制轉換成byte類型的值。
short var1 = 5; byte var2 = 10; var2 = (byte) var1; //強制轉換,將var1的值轉換成byte類型
二 隱式轉換
有些類型的轉換不會丟失數據與精度,如將8位的值轉換成16位的值是非常容易的,不會丟失精度。
C#語言會自動進行轉換,稱為隱式轉換。
從位數更少的源轉換成位數更多的目標類型時,目標中多出的位需要用0或1填充。
當從更小的無符號類型轉換為更大的無符號類型時,目標類型多出的最高位都以0進行填充,這叫做零擴展。
下圖演示使用零擴展將8位的10轉換成16位的10:
對於有符號類型的轉換而言,額外的高位用源表達式的符號位進行填充,這樣就維持了被轉換值的正確符號和大小。
下圖演示符號擴展:
三 顯示轉換和強制轉換
嘗試將ushort值1365轉換為byte值,會導致數據丟失。
對於預定義類型,C#會自動將一個數據類型轉換成另一個數據類型,但只是針對那些從源類型到目標類型不會發生數據丟失的情況。
而對於從源類型到目標類型轉換會發生數據丟失的情況,C#不提供自動轉換,就需要使用顯示轉換。這叫做強制轉換表達式。
四 轉換的類型
有很多標準的、預定義的用於數字和引用的轉換。
除了標準轉換,還可以為自定義類型定義隱式轉換和顯示轉換。
裝箱:將值類型轉換為object類型、System.ValueType類型。
拆箱:將一個裝箱的值轉換為原始類型。
五 引用轉換
引用類型對象有記憶體中的兩部分組成:引用和數據。
由引用保存的那部分信息是它指向的數據類型。
引用轉換接受源引用並返回一個指向堆中同一位置的引用,但是把引用標記為轉換的目標類型。
下例給出兩個引用變數,myVar1和myVar2,它們指向記憶體中的相同對象。
class Program { static void Main(string[] args) { B myVar1 = new B(); A myVar2 = (A)myVar1; //將myVar1作為A類的引用返回 Console.WriteLine(myVar1.Field1); //正確 Console.WriteLine(myVar2.Field2); //錯誤,Field2對於myVar2不可見 } } class A { public int Field1; } class B : A { public int Field2; }
5.1 隱式引用轉換
C#可以自動實現隱式引用轉換。
- 所有引用類型都可以被隱式轉換為object類型;
- 任何類型可以隱式轉換到它繼承的介面;
- 類可以隱式轉換到它繼承鏈中的任何類和它實現的任何介面。
5.2 顯示引用轉換
顯示引用轉換是從一個普通類型到一個更精確類型的引用轉換。
顯示轉換包括:
- 從object到任何引用類型的轉換;
- 從基類到從它繼承的類的轉換。
六 裝箱轉換和拆箱轉換
6.1 裝箱轉換
裝箱是一種隱式轉換,它接受值類型的值,根據這個值在堆中創建一個完整的引用類型對象並返回對象引用。
6.2 拆箱轉換
拆箱是把裝箱後的對象轉換回值類型對象的過程。
拆箱是顯示轉換。
系統在把值拆箱成ValueTypeT時執行瞭如下步驟:
- 它檢測到要拆箱的對象實際是ValueTypeT的裝箱值;
- 它把對象的值複製到變數。
七 用戶自定義轉換
除了標準轉換,我們還可以為類和結構自定義隱式轉換和顯示轉換。
語法如下:
public static implicit operator TargetType (SourceType Identifier) { . . . return ObjectOfTargetType }
用戶自定義轉換的約束:
- 只可以為類和結構定義用戶自定義轉換;
- 不能重定義標準隱式轉換或顯示轉換;
- 對於源類型S和目標類型T,S和T必須是不同類型;
- S和T不能通過繼承關聯,S和T都不能是介面類型或object類型;
- 轉換運算符必須是S或T的成員。
implicit:隱式轉換
explicit:顯示轉換,需要強制轉換表達式
下麵演示一個用戶自定義轉換的例子:
class Program { static void Main(string[] args) { Person bill = new Person("bill", 25); int age = bill; //將Person對象轉換為int Console.WriteLine($"Person Info :{bill.Name},{age}"); Person none = 35; //將int轉換為Person對象 Console.WriteLine($"Person Info :{none.Name},{none.Age}"); //輸出: //Person Info :bill,25 //Person Info :none,35 } } class Person { public string Name; public int Age; public Person(string name, int age) { Name = name; Age = age; } //將Person隱式轉換為int public static implicit operator int(Person p) { return p.Age; } //將int隱式轉換為Person public static implicit operator Person(int i) { return new Person("none", i); } }
八 is運算符和as運算符
有些轉換是非法的,會在運行時拋出一個InvalidCastException異常。我們可以使用Is運算符來檢查轉換是否會成功完成。
as運算符和強制轉換運算符類似,只是它不拋出異常。如果轉換失敗,它返回null而不是拋出異常。
class Program { static void Main(string[] args) { var student = new Student(); student.Name = "jack"; student.Age = 16; // is 第1種用法:檢測student是否能轉換為Person類型,如果可以,則返回true if (student is Person) { Console.WriteLine("stundent is Person"); } // is 第2種用法:檢測student是否能轉換為Person類型,如果可以,則返回true,並將其轉換賦值給Person類型的變數p if (student is Person p) { Console.WriteLine($"Person p:{p.Name},{p.Age}"); } // as 用法 var p1 = student as Person; if (p1 != null) { Console.WriteLine($"Person p:{p1.Name},{p1.Age}"); } } } class Person { public string Name; public int Age; } class Student : Person { }