1. 程式人生 > 其它 >詳解 C# 中的裝箱與拆箱

詳解 C# 中的裝箱與拆箱

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