Desenvolvimento - C#
Boxing e Unboxing em .NET
Este artigo explica os conceitos básicos de Boxing e Unboxing em .NET e uma breve explicação sobre tipos de dados.
por Cristian FernandesO .NET Framework possui duas grandes divisões em seus tipos de dados, os Value Types (Tipos por Valor) e os Reference Types (Tipos por Referência). Os Value Types são armazenados na stack e os Reference Types são armazenados na heap.
Chamamos de Boxing a conversão de um Value Type para um Reference Type e à conversão de volta de um Reference Type para um Value Type damos o nome de Unboxing.Agora uma breve explicação sobre tipos no Framework:
Value Types (Tipos por Valor)
Value Types são tipos primitivos que são mapeados diretamente ao FCL(Biblioteca de Classes do Framework), como por exemplo o tipo Int32 vem do System.Int32, o tipo double vem do System.double. Todos os Value Types são armazenados na stack e são derivados de System.ValueType. Resumindo, uma variável declarada como um tipo de dados por valor é estruturada na memória para conter um valor diretamente.
Ex: Byte, Integer, Single, Double, Boolean, Char, Struct, Enum e etc...
Reference Types (Tipos por Referência)
Reference Types são diferentes dos Value Types, porque são criados, e armazenados no heap. Todas as classes que criamos são do Reference Type. O Operador "new" retorna o endereço de memória do objeto no heap. Resumindo, uma variável declara como um tipo de dados por referência é estruturada para conter uma referência para um objeto atual na heap. Uma referência é um endereço de memória onde um objeto existe na heap.
Vamos ver alguns exemplos para um melhor entendimento de Value e Reference Types. Sabendo que todos os Value Types são derivados de System.ValueTypes nós podemos codificar algo como isto:
System.ValueType T = 5;
Será que isso compila?
Sim, isto compila.
Mas espera aí, eu não me lembro de ter ouvido falar de nenhum tipo chamado System.ValueType, o que sei é que ela é a classe base de onde todos os Value Types são herdados.
Exatamente, mas na verdade a variável T se refere a um System.Int32, ou seja um Int32.
Agora você me pergunta novamente, por que um Int32 e não um Int16 ou algum outro tipo.Na verdade isso ocorre devido a inicialização que fizemos nesta variável, ela assume um tipo de acordo com a sua inicialização, você pode ver com seus próprios olhos através do Método GetType() como por exemplo:
System.ValueType T = 5; Console.WriteLine(T.GetType()); // Isto retornará System.Int32, pode testar
Lembrando também que algo tipo isto, não funciona:
System.ValueType T = 5; T++;
Isto não funciona porque a variável T não é de um tipo primitivo e sim de uma classe base de um tipo primitivo que não aceita este tipo de operadores matemáticos.
Agora vamos aos exemplos de Boxing e Unboxing:
Boxing: É a conversão de um Value Type para um Reference Type, vamos ver no exemplo abaixo, neste exemplo eu mostro dois tipos de Boxing um explicito utilizando a conversão para object e outro implicito onde eu não preciso dizer para o compilador que vai haver uma conversão, ele se vira sozinho e resolve o problema.
Int32 x = 10; object o = x ; // Boxing Implicito Console.WriteLine("O objeto o = {0}",o); // Imprime 10 na tela Int32 x = 10; object o = (object) x; // Boxing Explicito Console.WriteLine("O Objeto o = {0}",o); // Imprime 10 na tela
Unboxing: É quando um Reference Type (object) volta a ser um Value Type.Temos abaixo um exemplo bem simples de Unboxing onde transformamos um object novamente para uma variável do tipo Int32, lembrando que antes de fazer o Unbox é necessário fazer o Box.
Int32 x = 5; object o = x; // Boxing Implícito x = o; // UnBoxing Implícito
Você viu como é simples fazer o Box e Unbox.O exemplo acima primeiro transforma uma variável Int32 para um object e depois simplesmente faz o unbox desta variável para x novamente. Todas as conversões ocorrem de maneira implícita, tudo parece ok neste exemplo, mas há um pequeno grande problema que faz este código acima não compilar.
Você não pode fazer uma conversão implicita de um Reference Type para um Value Type, você tem que "dizer com todas as letras" que quer fazer o Unbox do seu objeto, assim:
Int32 x = 5; object o = x; // Boxing Implícito x = (Int32)o; // UnBoxing Explícito
Vamos ver mais um exemplo de Unboxing:
Int32 x = 5; // Declarando Int32 Int64 y = 0; // Declarando Int64 double object o = x; // Boxing Implícito y = (Int64)o; // Unboxing Explicito para double Console.WriteLine("y={0}",y);
Mais uma vez o exemplo não irá funcionar, irá compilar normalmente, entretanto ocorrerá um erro em tempo de execução, na verdade será gerada uma exception do tipo System.InvalidCastException.
O motivo é que a variável x foi convertida para object (boxing) como Int32 então o tipo da variável deve permanecer o mesmo, ou seja quando for feito o unbox desta variável deve ser para uma variável Int32, mas se você mesmo assim quiser converter para um Int64 você pode fazer o seguinte:
Int32 x = 5; // Declarando Int32 Int64 y = 0; // Declarando Int64 double object o = x; // Boxing Implicito y = (Int64)(Int32)o; // Unboxing e depois convertendo pra double Console.WriteLine("y={0}",y);
Espero que tenha contribuído para um entendimento inicial do conceito de Boxing e Unboxing em .NET.
Abraços,
Cristian Fernandes