Share via


Boxning och unboxing (C#-programmeringsguide)

Boxning är processen att konvertera en värdetyp till typen object eller till någon gränssnittstyp som implementeras av den här värdetypen. När CLR (Common Language Runtime) rutor en värdetyp omsluter det värdet i en System.Object instans och lagrar det på den hanterade heapen. Om du tar bort rutor extraheras värdetypen från objektet. Boxning är implicit; unboxing är explicit. Begreppet boxning och unboxing ligger till grund för den enhetliga C#-vyn av typsystemet där ett värde av vilken typ som helst kan behandlas som ett objekt.

I följande exempel är heltalsvariabeln i rutad och tilldelad till objektet o.

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

Objektet o kan sedan tas bort och tilldelas till heltalsvariabeln i:

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

Följande exempel illustrerar hur boxning används i 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

Prestanda

När det gäller enkla tilldelningar är boxning och unboxing beräkningsmässigt dyra processer. När en värdetyp boxas måste ett nytt objekt allokeras och konstrueras. I mindre grad är den rollbesättning som krävs för unboxing också dyr beräkning. Mer information finns i Prestanda.

Boxning

Boxning används för att lagra värdetyper i skräpinsamlingshögen. Boxning är en implicit konvertering av en värdetyp till typen object eller till någon gränssnittstyp som implementeras av den här värdetypen. Boxning av en värdetyp allokerar en objektinstans på heapen och kopierar värdet till det nya objektet.

Överväg följande deklaration av en värdetypsvariabel:

int i = 123;

Följande instruktion tillämpar implicit boxningsåtgärden på variabeln i:

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

Resultatet av den här instruktionen skapar en objektreferens o, på stacken, som refererar till ett värde av typen int, på heapen. Det här värdet är en kopia av värdet av värdetypen som tilldelats variabeln i. Skillnaden mellan de två variablerna och io, illustreras i följande bild av boxningskonvertering:

Bild som visar skillnaden mellan variablerna i och o.

Det är också möjligt att utföra boxningen explicit som i följande exempel, men explicit boxning krävs aldrig:

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

Exempel

I det här exemplet konverteras en heltalsvariabel i till ett objekt o med hjälp av boxning. Sedan ändras värdet som lagras i variabeln i från 123 till 456. Exemplet visar att den ursprungliga värdetypen och det boxade objektet använder separata minnesplatser och därför kan lagra olika värden.

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

Avboxning är en explicit konvertering från typen object till en värdetyp eller från en gränssnittstyp till en värdetyp som implementerar gränssnittet. En avboxningsåtgärd består av:

  • Kontrollera objektinstansen för att se till att det är ett rutat värde av den angivna värdetypen.

  • Kopiera värdet från instansen till variabeln värdetyp.

Följande instruktioner visar både boxnings- och avboxningsåtgärder:

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

Följande bild visar resultatet av föregående instruktioner:

Bild som visar en konvertering som avboxas.

För att avboxning av värdetyper ska lyckas vid körning måste objektet som tas bort från rutan vara en referens till ett objekt som tidigare skapades genom boxning av en instans av den värdetypen. Om du försöker ta bort rutan null orsakas en NullReferenceException. Om du försöker ta bort en referens till en inkompatibel värdetyp orsakas en InvalidCastException.

Exempel

I följande exempel visas ett fall av ogiltig avboxning och resulterande InvalidCastException. Med och trycatchvisas ett felmeddelande när felet inträffar.

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

Det här programmet matar ut:

Specified cast is not valid. Error: Incorrect unboxing.

Om du ändrar -instruktionen:

int j = (short)o;

till:

int j = (int)o;

konverteringen utförs och du får utdata:

Unboxing OK.

Språkspecifikation för C#

Mer information finns i C#-språkspecifikationen. Språkspecifikationen är den slutgiltiga källan för C#-syntax och -användning.

Se även