Na rede:
Freqüentemente, você não pode confiar no tipo de variável que uma função consumirá; portanto, é necessário usar uma variável de objeto que se estende do menor denominador comum - em .Net, este é object
.
No entanto, object
é uma classe e armazena seu conteúdo como referência.
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
Enquanto ambos mantêm a mesma informação, a segunda lista é maior e mais lenta. Cada valor na segunda lista é na verdade uma referência a um object
que contém o int
.
Isso é chamado de caixa porque o int
é envolvido pelo object
. Quando ele é lançado fora da int
caixa - convertido de volta ao seu valor.
Para tipos de valor (isto é, todos structs
), isso é lento e potencialmente usa muito mais espaço.
Para tipos de referência (isto é, todos classes
), isso é muito menos problemático, pois eles são armazenados como referência de qualquer maneira.
Um outro problema com um tipo de valor em caixa é que não é óbvio que você está lidando com a caixa, e não com o valor. Quando você compara dois structs
, você está comparando valores, mas quando você compara dois, classes
então (por padrão), você está comparando a referência - ou seja, essas são a mesma instância?
Isso pode ser confuso ao lidar com tipos de valor em caixa:
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
É fácil contornar:
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
No entanto, é outra coisa a ter cuidado ao lidar com valores em caixa.