詳解 C# 中的裝箱與拆箱
阿新 • • 發佈:2022-04-19
在C#中,裝箱(boxing)是把值型別轉換為System.Object型別,或者轉換為由值型別實現的介面型別。拆箱(unboxing)是相反的轉換過程。
例如,以下結構型別:
struct MyStruct
{
public int Val;
}
注:struct 結構體是值型別。
可以把這種型別的結構放在object型別的變數中,對其裝箱:
MyStruct valType1 = new MyStruct();
valType1.Val = 1;
object refType = valType1;
其中建立了一個型別為MyStruct的新變數valType1,並把一個值"1"賦予這個結構的Val成員,然後把它裝箱在object型別的變數refType中。
以這種方式裝箱變數而建立的物件,會包含值型別變數的一個副本的引用,而不包含源值型別變數的引用。要進行驗證,可以修改源結構的內容,把物件中包含的結構拆箱到新變數中,檢查其內容:
valType1.Val = 2;
MyStruct valType2 = (MyStruct)refType;
WriteLine($"valType2.Val = {valType2.Val}");
執行這段程式碼將得到如下輸出結果: valType2.Val = 1
但在把一個引用型別賦予物件時,將執行不同的操作。把MyStruct改為一個類(不考慮這個類名不合適的情況),即可看到這種情形:
class
MyStruct
{
public int Val;
}
如果不修改上面的客戶程式碼(再次忽略名稱有誤的變數),就會得到如下輸出結果: valType2.Val = 2
也可以把值型別裝箱到介面型別中,只要它們實現這個介面即可。例如,假定MyStruct型別實現IMyInterface介面,如下所示:
interface IMyInterface {}
struct MyStruct : IMyInterface
{
public int Val;
}
接著把結構裝箱到一個IMyInterface型別中,如下所示:
MyStruct valType1 = new MyStruct();
IMyInterface refType = valType1;
然後使用一般的資料型別轉換語法對其拆箱: MyStruct ValType2 = (MyStruct)refType;
從這些示例中可以看出,裝箱是在沒有使用者干涉的情況下進行的(即不需要編寫任何程式碼),但拆箱一個值需要進行顯式轉換,即需要進行資料型別轉換(裝箱是隱式的,所以不需要進行資料型別轉換)。
您可能想知道為什麼要這麼做。裝箱非常有用,有兩個非常重要的原因。首先,它允許在項的型別是object的集合(如ArrayList)中使用值型別。其次,有一個內部機制允許在值型別(例如int和結構)上呼叫object方法。
最後需要注意的是,在訪問值型別內容前,必須進行拆箱。