Boxing 和 Unboxing (C# 程式設計手冊)

Boxing 是將實值型別轉換為 object 類型或是由這個實值型別實作之任何介面類型的程序。 當 Common Language Runtime (CLR) 方塊實值類型時,它會將值包裝在 實例內 System.Object ,並將其儲存在 Managed 堆積上。 Unbox 處理則會從物件中擷取實值類型。 Boxing 是隱含處理,unboxing 則是明確處理。 Boxing 和 unboxing 的概念是 C# 類型系統統一檢視的基礎,其中任何類型的值都可視為物件。

在下列範例中,整數變數 i 會經過 Box 處理並且指派給 o 物件。

int i = 123;
// The following line boxes i.
object o = i;

接著就可以對物件 o 進行 Unbox 處理,並將該物件指派給整數變數 i

o = 123;
i = (int)o;  // unboxing

下列範例將說明在 C# 中使用 boxing 的方式。

// String.Concat example.
// String.Concat has many versions. Rest the mouse pointer on
// Concat in the following statement to verify that the version
// that is used here takes three object arguments. Both 42 and
// true must be boxed.
Console.WriteLine(String.Concat("Answer", 42, true));

// List example.
// Create a list of objects to hold a heterogeneous collection
// of elements.
List<object> mixedList = new List<object>();

// Add a string element to the list.
mixedList.Add("First Group:");

// Add some integers to the list.
for (int j = 1; j < 5; j++)
{
    // Rest the mouse pointer over j to verify that you are adding
    // an int to a list of objects. Each element j is boxed when
    // you add j to mixedList.
    mixedList.Add(j);
}

// Add another string and more integers.
mixedList.Add("Second Group:");
for (int j = 5; j < 10; j++)
{
    mixedList.Add(j);
}

// Display the elements in the list. Declare the loop variable by
// using var, so that the compiler assigns its type.
foreach (var item in mixedList)
{
    // Rest the mouse pointer over item to verify that the elements
    // of mixedList are objects.
    Console.WriteLine(item);
}

// The following loop sums the squares of the first group of boxed
// integers in mixedList. The list elements are objects, and cannot
// be multiplied or added to the sum until they are unboxed. The
// unboxing must be done explicitly.
var sum = 0;
for (var j = 1; j < 5; j++)
{
    // The following statement causes a compiler error: Operator
    // '*' cannot be applied to operands of type 'object' and
    // 'object'.
    //sum += mixedList[j] * mixedList[j];

    // After the list elements are unboxed, the computation does
    // not cause a compiler error.
    sum += (int)mixedList[j] * (int)mixedList[j];
}

// The sum displayed is 30, the sum of 1 + 4 + 9 + 16.
Console.WriteLine("Sum: " + sum);

// Output:
// Answer42True
// First Group:
// 1
// 2
// 3
// 4
// Second Group:
// 5
// 6
// 7
// 8
// 9
// Sum: 30

效能

相對於單純的指派,boxing 和 unboxing 是會耗費大量運算資源的處理序。 當實值類型經過 Box 處理時,必須配置及建構新的物件。 Unboxing 所需的轉換雖然較為簡單,但也同樣需要大量運算資源。 如需詳細資訊,請參閱效能

Box 處理

Boxing 可用來儲存記憶體回收堆積中的實值類型。 Boxing 是一種隱含轉換,可將實值型別轉換為 object 類型,或是由這個實值型別實作的任何介面類型。 對實值類型進行 Boxing 處理時,會在堆積上配置物件執行個體,並將值複製到新物件中。

請考慮下列實值類型變數的宣告:

int i = 123;

下列陳述式會以隱含方式對變數 i 套用 boxing 作業:

// Boxing copies the value of i into object o.
object o = i;

這個陳述式的結果是在堆疊上建立物件參考 o,用於參考堆積中 int 類型的值。 這個值是指派給變數 i 之實值類型值的複本。 io 這兩個變數之間的差異如下方 Boxing 轉換圖所示:

Graphic showing the difference between i and o variables.

您也可以執行明確的 boxing 處理,如同下列範例中所示,但是明確的 boxing 處理並非必要:

int i = 123;
object o = (object)i;  // explicit boxing

範例

這個範例會使用 Boxing 將整數變數 i 轉換為物件 o。 接著,儲存在變數 i 中的值就會從 123 變更為 456。 這個範例顯示,原始實值類型以及經過 Box 處理的物件分別使用不同的記憶體位置,因此可以儲存不同的值。

class TestBoxing
{
    static void Main()
    {
        int i = 123;

        // Boxing copies the value of i into object o.
        object o = i;

        // Change the value of i.
        i = 456;

        // The change in i doesn't affect the value stored in o.
        System.Console.WriteLine("The value-type value = {0}", i);
        System.Console.WriteLine("The object-type value = {0}", o);
    }
}
/* Output:
    The value-type value = 456
    The object-type value = 123
*/

Unbox 處理

Unboxing 是將 object 類型明確轉換為實值型別,或將介面類型明確轉換為實作介面之實值型別的程序。 Unboxing 作業包含:

  • 檢查物件執行個體,確定它是所指定實值類型經過 Box 處理的值。

  • 將值從執行個體複製到實值類型變數。

下列陳述式將示範 boxing 和 unboxing 作業:

int i = 123;      // a value type
object o = i;     // boxing
int j = (int)o;   // unboxing

下圖示範上述陳述式的結果:

Graphic showing an unboxing conversion.

若要在執行階段成功對實值類型進行 Unbox 處理,要進行 Unbox 處理的項目必須是物件的參考,而且該物件是先前對該實值類型的執行個體進行 Box 處理所建立的物件。 嘗試對 null 進行 Unbox 處理會造成 NullReferenceException。 嘗試對不相容的實值類型參考進行 Unbox 處理會造成 InvalidCastException

範例

下列範例將示範 Unboxing 無效且產生 InvalidCastException 的案例。 若使用 trycatch,則會在發生錯誤時顯示錯誤訊息。

class TestUnboxing
{
    static void Main()
    {
        int i = 123;
        object o = i;  // implicit boxing

        try
        {
            int j = (short)o;  // attempt to unbox

            System.Console.WriteLine("Unboxing OK.");
        }
        catch (System.InvalidCastException e)
        {
            System.Console.WriteLine("{0} Error: Incorrect unboxing.", e.Message);
        }
    }
}

這個程式會輸出:

Specified cast is not valid. Error: Incorrect unboxing.

如果您將陳述式:

int j = (short)o;

變更為:

int j = (int)o;

轉換將會執行,而且您會得到下列輸出結果:

Unboxing OK.

C# 語言規格

如需詳細資訊,請參閱<C# 語言規格>。 語言規格是 C# 語法及用法的限定來源。

另請參閱