En la red:
A menudo no puede confiar en el tipo de variable que consumirá una función, por lo que debe usar una variable de objeto que se extienda desde el mínimo común denominador, en .Net esto es object
.
Sin embargo, object
es una clase y almacena su contenido como referencia.
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
Si bien ambos contienen la misma información, la segunda lista es más grande y más lenta. Cada valor en la segunda lista es en realidad una referencia a un object
que contiene el int
.
Esto se llama en caja porque int
está envuelto por object
. Cuando se vuelve a lanzar, int
se desempaqueta: se vuelve a convertir en su valor.
Para los tipos de valor (es decir, todos structs
) esto es lento y potencialmente usa mucho más espacio.
Para los tipos de referencia (es decir, todos classes
) esto es mucho menos problemático, ya que de todos modos se almacenan como referencia.
Otro problema con un tipo de valor en caja es que no es obvio que se trata de la caja, en lugar del valor. Cuando compara dos, structs
entonces está comparando valores, pero cuando compara dos, classes
entonces (por defecto) está comparando la referencia, es decir, ¿son la misma instancia?
Esto puede ser confuso cuando se trata de tipos de valores encuadrados:
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
Es fácil evitarlo:
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
Sin embargo, es otra cosa a tener en cuenta cuando se trata de valores encuadrados.