Dela via


Boxning och avboxning (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) boxar en värdetyp omsluter den värdet i en System.Object-instans och lagrar det på en hanterad heap. Avboxing extraherar värdetypen från objektet. Boxning är implicit; unboxing är explicit. Begreppet boxing och unboxing ligger till grund för den enhetliga vyn av C#-typsystemet där ett värde av vilken typ som helst kan behandlas som ett objekt.

I följande exempel är heltalsvariabeln irutad 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 avboxning 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 i heapminnet 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å heap. Det här värdet är en kopia av värdet av värdetypen som tilldelats variabeln i. Skillnaden mellan de två variablerna, i och o, illustreras i följande bild av boxningskonvertering:

Bild som visar skillnaden mellan i- och o-variabler.

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.

        // Create an int variable
        int i = 123;
        
        // Box the value type into an object reference
        object o = i;  // boxing
        
        // Display the initial values
        Console.WriteLine($"Value of i: {i}");
        Console.WriteLine($"Value of boxed object o: {o}");
        
        // Modify the original value type
        i = 456;
        
        // Display the values after modification
        Console.WriteLine("\nAfter changing i to 456:");
        Console.WriteLine($"Value of i: {i}");
        Console.WriteLine($"Value of boxed object o: {o}");
        
        // Output:
        // Value of i: 123
        // Value of boxed object o: 123

        // After changing i to 456:
        // Value of i: 456
        // Value of boxed object o: 123

Öppna förpackningen

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 uppackningskonvertering.

För att uppackning av värdetyper ska lyckas vid körning måste objektet som packas upp vara en referens till ett objekt som tidigare skapades genom boxning av en instans av samma värdetyp. Försöker du packa upp null orsakar det en NullReferenceException. Om du försöker ta bort en referens till en inkompatibel värdetyp orsakas en InvalidCastException.

Exempel

I följande exempel demonstreras ett fall av ogiltig uppackning och dess resulterande InvalidCastException. Med hjälp av try och catchvisas 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($"{e.Message} Error: Incorrect unboxing.");
        }
    }
}

Det här programmet matar ut:

Specified cast is not valid. Error: Incorrect unboxing.

Om du ändrar uttalandet:

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