在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方法。
最后需要注意的是,在訪問值類型內容前,必須進行拆箱。