C#基礎之轉換
一 什麼是轉換
轉換是接受一個類型的值并使用它作為另一個類型的等價值的過程。
下列代碼示範了将1個short類型的值強制轉換成byte類型的值。
short var1 = 5;
byte var2 = 10;
var2 = (byte) var1; //強制轉換,将var1的值轉換成byte類型
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL0YDM3gTO3EDOx0SO3gDM0kTNwIjNwUDMyIDMy0iM1AzM5MjMvwVNwIjMwIzLcJTNwMTOzIzLcd2bsJ2Lc12bj5ycn9Gbi52YuIjMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
二 隐式轉換
有些類型的轉換不會丢失資料與精度,如将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 { }