Partager via


Boxing et unboxing (Guide de programmation C#)

Boxing est le processus de conversion d’un type valeur en type object ou en n’importe quel type d’interface implémenté par ce type valeur. Lorsque le Common Language Runtime (CLR) boxe un type de valeur, il encapsule la valeur à l’intérieur d’une System.Object instance et le stocke sur le tas managé. L'unboxing extrait le type valeur de l'objet. La conversion boxing est implicite ; la conversion unboxing est explicite. Le concept de boxe et de déboxing sous-tend l’affichage unifié C# du système de type dans lequel une valeur de n’importe quel type peut être traitée comme un objet.

Dans l’exemple suivant, la variable i entière est boxée et affectée à l’objet o.

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

L’objet o peut ensuite être unboxed et affecté à la variable ientière :

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

Les exemples suivants illustrent l’utilisation de boxe en 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

Performances

En ce qui concerne les affectations simples, la boxe et le déboxing sont des processus coûteux en termes de calcul. Lorsqu’un type valeur est boxé, un nouvel objet doit être alloué et construit. Dans une moindre mesure, la conversion requise pour unboxing est également coûteuse en calcul. Pour plus d’informations, consultez Performance.

Boxe

La boxe est utilisée pour stocker les types de valeurs dans le tas collecté par le garbage. Boxing est une conversion implicite d’un type valeur en type object ou en n’importe quel type d’interface implémenté par ce type valeur. La boxe d’un type valeur alloue une instance d’objet sur le tas et copie la valeur dans le nouvel objet.

Considérez la déclaration suivante d’une variable de type valeur :

int i = 123;

L’instruction suivante applique implicitement l’opération de boxe sur la variable i:

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

Le résultat de cette instruction est la création d’une référence od’objet , sur la pile, qui fait référence à une valeur du type int, sur le tas. Cette valeur est une copie de la valeur de type valeur affectée à la variable i. La différence entre les deux variables et o, i est illustrée dans l’image suivante de la conversion de boxe :

Graphique montrant la différence entre les variables i et o.

Il est également possible d’effectuer explicitement la boxe comme dans l’exemple suivant, mais la boxe explicite n’est jamais nécessaire :

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

Exemple :

Cet exemple convertit une variable i entière en objet o à l’aide de la boxe. Ensuite, la valeur stockée dans la variable i est remplacée par 123456. L’exemple montre que le type de valeur d’origine et l’objet boxed utilisent des emplacements de mémoire distincts et peuvent donc stocker différentes valeurs.

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

Déballage

Unboxing est une conversion explicite du type object en type valeur ou d’un type d’interface vers un type valeur qui implémente l’interface. Une opération d’annulation de boîte de réception se compose des éléments suivants :

  • Vérification de l’instance d’objet pour vous assurer qu’il s’agit d’une valeur boxée du type valeur donné.

  • Copie de la valeur de l’instance dans la variable de type valeur.

Les instructions suivantes illustrent les opérations boxing et unboxing :

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

La figure suivante illustre le résultat des instructions précédentes :

Graphique montrant une conversion d’unboxing.

Pour que le déboxing des types valeur réussisse au moment de l’exécution, l’élément qui est unboxed doit être une référence à un objet qui a été créé précédemment en boxant une instance de ce type valeur. La tentative d’annulation de la boîte de réception null provoque un NullReferenceException. La tentative d’annulation de la boîte de réception d’une référence à un type valeur incompatible provoque un InvalidCastException.

Exemple :

L’exemple suivant illustre un cas d’unboxing non valide et du résultat InvalidCastException. Utilisation try et catch, un message d’erreur s’affiche lorsque l’erreur se produit.

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

Ce programme génère les résultats suivants :

Specified cast is not valid. Error: Incorrect unboxing.

Si vous modifiez l’instruction :

int j = (short)o;

vers :

int j = (int)o;

la conversion est effectuée et vous obtiendrez la sortie :

Unboxing OK.

Spécification du langage C#

Pour plus d'informations, voir la spécification du langage C#. La spécification du langage est la source de référence pour la syntaxe C# et son utilisation.

Voir aussi