Konwersja boxing i konwersja unboxing (Przewodnik programowania w języku C#)

Boxing to proces konwertowania typu wartości na typobject lub do dowolnego typu interfejsu zaimplementowanego przez ten typ wartości. Gdy środowisko uruchomieniowe języka wspólnego (CLR) tworzy typ wartości, opakowuje wartość w wystąpieniu i przechowuje ją na zarządzanym System.Object stosie. Rozpakowywanie wyodrębnia typ wartości z obiektu. Boxing jest niejawny; rozpatywanie jest jawne. Koncepcja boksowania i rozpakowania łączy ujednolicony widok języka C# systemu typów, w którym wartość dowolnego typu może być traktowana jako obiekt.

W poniższym przykładzie zmienna i całkowita jest w polu i przypisana do obiektu o.

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

Następnie obiekt o może być rozpakowane i przypisane do zmiennej całkowitej i:

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

Poniższe przykłady ilustrują sposób użycia boksu w języku C#.

// 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

Wydajność

W odniesieniu do prostych przypisań boxing i rozpboxing są kosztownymi procesami obliczeniowymi. W przypadku pola typu wartości należy przydzielić i skonstruować nowy obiekt. W mniejszym stopniu rzutowanie wymagane do rozpboxowania jest również kosztowne w obliczeniach. Aby uzyskać więcej informacji, zobacz Wydajność.

Boxing

Boxing służy do przechowywania typów wartości w stercie zbieranym przez śmieci. Boxing to niejawna konwersja typu wartości na typ object lub dowolny typ interfejsu zaimplementowany przez ten typ wartości. Typ wartości boxing przydziela wystąpienie obiektu na stercie i kopiuje wartość do nowego obiektu.

Rozważmy następującą deklarację zmiennej typu wartości:

int i = 123;

Następująca instrukcja niejawnie stosuje operację boxing na zmiennej i:

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

Wynikiem tej instrukcji jest utworzenie odwołania do oobiektu , na stosie, który odwołuje się do wartości typu int, na stercie. Ta wartość jest kopią wartości typu wartości przypisanej do zmiennej i. Różnica między dwiema zmiennymi i i o, przedstawiono na poniższej ilustracji konwersji boksu:

Graphic showing the difference between i and o variables.

Istnieje również możliwość jawnego wykonania boxingu, jak w poniższym przykładzie, ale jawne boxing nigdy nie jest wymagane:

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

Przykład

W tym przykładzie zmienna i całkowita jest konwertowana na obiekt o przy użyciu funkcji boxing. Następnie wartość przechowywana w zmiennej i jest zmieniana z 123 na 456. W przykładzie pokazano, że oryginalny typ wartości i poletowany obiekt używają oddzielnych lokalizacji pamięci, a zatem może przechowywać różne wartości.

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
*/

Unboxing

Rozpatywanie to jawna konwersja typu na typ objectwartości lub typ interfejsu na typ wartości implementujący interfejs. Operacja rozpychania składa się z:

  • Sprawdzanie wystąpienia obiektu w celu upewnienia się, że jest to pole wartości danego typu wartości.

  • Kopiowanie wartości z wystąpienia do zmiennej typu wartości.

Poniższe instrukcje przedstawiają operacje boksowania i rozpakowania:

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

Na poniższej ilustracji przedstawiono wynik poprzednich instrukcji:

Graphic showing an unboxing conversion.

Aby rozpiętywanie typów wartości powiodło się w czasie wykonywania, element, który jest rozpakowany, musi być odwołaniem do obiektu, który został wcześniej utworzony przez pole wystąpienia tego typu wartości. Próba rozpalokowania null powoduje, że element NullReferenceException. Próba rozpakowania odwołania do niezgodnego typu wartości powoduje błąd InvalidCastException.

Przykład

W poniższym przykładzie pokazano przypadek nieprawidłowego rozpalokowania i wynikowego InvalidCastExceptionelementu . catchW przypadku wystąpienia błędu w przypadku wystąpienia błędu jest wyświetlany komunikat o błędzie i try .

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);
        }
    }
}

Dane wyjściowe tego programu:

Specified cast is not valid. Error: Incorrect unboxing.

Jeśli zmienisz instrukcję:

int j = (short)o;

na:

int j = (int)o;

zostanie wykonana konwersja i uzyskasz dane wyjściowe:

Unboxing OK.

specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz Specyfikacja języka C#. Specyfikacja języka jest ostatecznym źródłem informacji o składni i użyciu języka C#.

Zobacz też