Condividi tramite


Boxing e unboxing (Guida per programmatori C#)

Il boxing è il processo di conversione di un tipo valore nel tipo object o in qualsiasi tipo di interfaccia implementato dal tipo valore. La conversione boxing di un tipo valore in CLR comporta il wrapping del valore in un System.Object e la sua archiviazione nell'heap gestito. L'unboxing consente invece di estrarre il tipo di valore dall'oggetto. La conversione boxing è implicita; quella unboxing è esplicita. Il concetto di conversione boxing e unboxing è alla base della visualizzazione unificata C# del sistema di tipi, in cui un valore di qualsiasi tipo può essere considerato come un oggetto.

Nell'esempio seguente viene eseguito il boxing della variabile integer i assegnandola all'oggetto o.

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

È quindi possibile eseguire l'unboxing dell'oggetto o assegnandolo alla variabile integer i:

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

Nell'esempio seguente viene illustrato l'utilizzo della conversione boxing 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

Prestazioni

Rispetto alle semplici assegnazioni, il boxing e l'unboxing sono processi onerosi dal punto di vista del calcolo. Il boxing di un tipo di valore comporta infatti l'allocazione e la costruzione di un nuovo oggetto. A un livello inferiore, anche il cast richiesto per l'unboxing è oneroso dal punto di vista del calcolo. Per ulteriori informazioni, vedere Prestazioni.

Boxing

Il boxing consente di archiviare tipi di valori nell'heap sottoposto a Garbage Collection. Il boxing è una conversione implicita di un tipo valore nel tipo object o in qualsiasi tipo di interfaccia implementato dal tipo valore. Il boxing di un tipo di valore prevede l'allocazione di un'istanza dell'oggetto nell'heap e quindi la copia del valore nel nuovo oggetto.

Si consideri la seguente dichiarazione di una variabile associata a un tipo che rappresenta un valore:

int i = 123;

L'istruzione seguente applica implicitamente l'operazione di boxing alla variabile i:

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

Il risultato di questa istruzione è la creazione, sullo stack, di un riferimento all'oggetto o che fa riferimento a un valore di tipo int presente sull'heap. Questo valore è una copia di quello del tipo che rappresenta un valore assegnato alla variabile i. La differenza tra le due variabili i e o è illustrata nella seguente figura.

Conversione boxing

Grafica BoxingConversion

È inoltre possibile, anche se non indispensabile, eseguire il boxing in modo esplicito, come nell'esempio seguente:

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

Oggetto di descrizione

In questo esempio la variabile integer i viene convertita in un oggetto o tramite boxing. Il valore archiviato nella variabile i viene quindi modificato da 123 a 456. Nell'esempio il tipo di valore originale e l'oggetto sottoposto a boxing utilizzano posizioni di memoria diverse, pertanto possono archiviare valori diversi.

Esempio

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 does not effect 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
*/

Nell'esempio riportato di seguito viene illustrato un caso di unboxing non valido, nonché l'eccezione InvalidCastException risultante. Se si utilizza try e catch, quando si verifica l'errore verrà visualizzato un messaggio di errore.

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

Questo programma restituisce:

Specified cast is not valid. Error: Incorrect unboxing.

Se si modifica l'istruzione:

int j = (short) o;

in:

int j = (int) o;

la conversione verrà eseguita e si otterrà l'output

Unboxing OK.

Conversione unboxing

L'unboxing è una conversione esplicita dal tipo object a un tipo di valore o da un tipo di interfaccia a un tipo di valore che implementa tale interfaccia. Un'operazione di unboxing consiste di due passaggi successivi:

  • Controllo dell'istanza di oggetto per verificare che si tratti di un valore già sottoposto a boxing del tipo di valore dato.

  • Copia del valore dall'istanza alla variabile associata al tipo che rappresenta un valore.

Le istruzioni seguenti illustrano operazioni di boxing e unboxing:

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

La figura che segue illustra il risultato delle istruzioni precedenti.

Conversione unboxing

Rappresentazione grafica della conversione di UnBoxing

Per il corretto unboxing dei tipi di valore in fase di esecuzione, è necessario che l'elemento di cui eseguire l'unboxing faccia riferimento a un oggetto creato in precedenza tramite il boxing di un'istanza di tale tipo di valore. Il tentativo di eseguire l'unboxing di null genera una NullReferenceException. Il tentativo di eseguire l'unboxing di un tipo di valore incompatibile genera una InvalidCastException.

Specifiche del linguaggio C#

Per ulteriori informazioni, vedere la Specifiche del linguaggio C#. La specifica del linguaggio è la fonte ufficiale per la sintassi e l'utilizzo di C#.

Sezioni correlate

Per ulteriori informazioni:

Specifiche del linguaggio C#

Per ulteriori informazioni, vedere la Specifiche del linguaggio C#. La specifica del linguaggio è la fonte ufficiale per la sintassi e l'utilizzo di C#.

Vedere anche

Concetti

Guida per programmatori C#

Cronologia delle modifiche

Data

Cronologia

Motivo

Luglio 2010

Chiarimento relativo all'introduzione e gli esempi aggiunti.

Commenti e suggerimenti dei clienti.