In .Net:
Spesso non puoi fare affidamento sul tipo di variabile che consumerà una funzione, quindi devi utilizzare una variabile oggetto che si estende dal minimo comune denominatore - in .Net questo è object.
Tuttavia objectè una classe e memorizza i suoi contenuti come riferimento.
List<int> notBoxed = new List<int> { 1, 2, 3 };
int i = notBoxed[1]; // this is the actual value
List<object> boxed = new List<object> { 1, 2, 3 };
int j = (int) boxed[1]; // this is an object that can be 'unboxed' to an int
Mentre entrambi contengono le stesse informazioni, il secondo elenco è più grande e più lento. Ogni valore nel secondo elenco è in realtà un riferimento a un objectche contiene il int.
Questo si chiama boxed perché intè racchiuso da object. Quando il cast viene restituito, intviene deselezionato - convertito nuovamente nel suo valore.
Per i tipi di valore (ovvero tutti structs), questo è lento e potenzialmente utilizza molto più spazio.
Per i tipi di riferimento (cioè tutti classes) questo è molto meno un problema, poiché sono comunque memorizzati come riferimento.
Un ulteriore problema con un tipo di valore inscatolato è che non è ovvio che hai a che fare con la scatola, piuttosto che con il valore. Quando si confrontano due, structssi confrontano i valori, ma quando si confrontano due, classesquindi (per impostazione predefinita) si confronta il riferimento, ovvero si tratta della stessa istanza?
Questo può essere fonte di confusione quando si tratta di tipi di valore inscatolati:
int a = 7;
int b = 7;
if(a == b) // Evaluates to true, because a and b have the same value
object c = (object) 7;
object d = (object) 7;
if(c == d) // Evaluates to false, because c and d are different instances
È facile aggirare:
if(c.Equals(d)) // Evaluates to true because it calls the underlying int's equals
if(((int) c) == ((int) d)) // Evaluates to true once the values are cast
Tuttavia è un'altra cosa a cui fare attenzione quando si ha a che fare con valori inscatolati.