Boksen en Uitpakken (C#-programmeerhandleiding)
Boksen is het proces van het omzetten van een waardetype naar het type object
of naar een interfacetype dat door dit waardetype wordt geïmplementeerd. Wanneer in de COMMON Language Runtime (CLR) een waardetype wordt ingesloten, wordt de waarde in een System.Object exemplaar verpakt en opgeslagen op de beheerde heap. Bij het unboxen wordt het waarde-type uit het object gehaald. Boksen is impliciet; het uitpakken is expliciet. Het concept van boxing en unboxing ligt ten grondslag aan de uniforme weergave van het C#-typesysteem, waarin een waarde van elk type kan worden behandeld als een object.
In het volgende voorbeeld wordt de integer-variabele i
als ingepakt en toegewezen aan object o
.
int i = 123;
// The following line boxes i.
object o = i;
Het object o
kan vervolgens worden uitgepakt en toegewezen aan een geheel getalvariabele i
:
o = 123;
i = (int)o; // unboxing
In de volgende voorbeelden ziet u hoe boksen wordt gebruikt in 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
Prestatie
Met betrekking tot eenvoudige toewijzingen zijn boksen en uitpakken rekenintensieve processen. Wanneer een waardetype in een vak wordt geplaatst, moet een nieuw object worden toegewezen en samengesteld. In mindere mate is de cast die nodig is voor het unboxen ook duur in termen van rekenkracht. Zie Performancevoor meer informatie.
Boksen
Boksen wordt gebruikt voor het opslaan van waardetypen in de verzamelde afval heap. Boksen is een impliciete omzetting van een waardetype naar het type object
of naar een interfacetype dat door dit waardetype wordt geïmplementeerd. Wanneer een waardetype wordt ingepakt, wordt er een object op de heap aangemaakt en de waarde naar het nieuwe object gekopieerd.
Overweeg de volgende declaratie van een waardetypevariabele:
int i = 123;
De volgende instructie past impliciet de boksbewerking toe op de variabele i
:
// Boxing copies the value of i into object o.
object o = i;
Het resultaat van deze instructie is het maken van een objectverwijzing o
, op de stapel, die verwijst naar een waarde van het type int
, op de heap. Deze waarde is een kopie van de waardetypewaarde die is toegewezen aan de variabele i
. Het verschil tussen de twee variabelen, i
en o
, wordt geïllustreerd in de volgende afbeelding van boksenconversie:
Het is ook mogelijk om de boksen expliciet uit te voeren zoals in het volgende voorbeeld, maar expliciet boksen is nooit vereist:
int i = 123;
object o = (object)i; // explicit boxing
Voorbeeld
In dit voorbeeld wordt een integer-variabele i
geconverteerd naar een object o
met behulp van de boxing-techniek. Vervolgens wordt de waarde die is opgeslagen in de variabele i
gewijzigd van 123
in 456
. In het voorbeeld ziet u dat het oorspronkelijke waardetype en het boxed-object afzonderlijke geheugenlocaties gebruiken en daarom verschillende waarden kunnen opslaan.
// 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
Uitpakken
Het uitpakken is een expliciete conversie van het type object
naar een waardetype of van een interfacetype naar een waardetype waarmee de interface wordt geïmplementeerd. Een unboxing-bewerking bestaat uit:
Controleren of het objectexemplaar een ingepakte waarde van het opgegeven waardetype is.
De waarde van de instantie kopiëren naar de waarde-type variabele.
De volgende uitspraken demonstreren zowel inpak- als uitpakbewerkingen:
int i = 123; // a value type
object o = i; // boxing
int j = (int)o; // unboxing
In de volgende afbeelding ziet u het resultaat van de vorige instructies:
Voor het uitpakken van waardetypen tijdens runtime moet het item dat wordt uitgepakt een verwijzing zijn naar een object dat eerder door boxing van een instantie van dat waardetype is gemaakt. Als u probeert null
uit te pakken, veroorzaakt dit een NullReferenceException. Wanneer u probeert een verwijzing naar een niet-compatibel waardetype uit te pakken, veroorzaakt dit een InvalidCastException.
Voorbeeld
In het volgende voorbeeld wordt een geval van ongeldige unboxing en het resulterende InvalidCastException
gedemonstreerd. Als u try
en catch
gebruikt, wordt er een foutbericht weergegeven wanneer de fout optreedt.
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.");
}
}
}
Dit programma voert het volgende uit:
Specified cast is not valid. Error: Incorrect unboxing.
Als u de verklaring wijzigt:
int j = (short)o;
Aan:
int j = (int)o;
de conversie wordt uitgevoerd en u krijgt de uitvoer:
Unboxing OK.
C#-taalspecificatie
Zie de C#-taalspecificatievoor meer informatie. De taalspecificatie is de definitieve bron voor de C#-syntaxis en het gebruik.