Fala galera, blz?
Sexta publicação da série introdução ao .Net Framework. Nesse post falarei sobre boxing e unboxing de tipos. Você sabia que pode estar realizando operações que podem estar diminuindo a performance do seu código?
Para quem não leu os post anteriores, recomendo que leiam, segue os link’s.
1 - Introdução ao .Net Framework - Parte 1 - Do que é composto, compialçao.
2 - Introdução ao .Net Framework - Parte 2 - CLR, CTS, FCL, CLS.
3 - Introdução ao .Net Framework - Parte 3 - Tipos.
4 - Introdução ao .Net Framework - Parte 4 - Conversão/Casting de tipos.
5 - Introdução ao .Net Framework - Parte 5 - Namespace e Assemblies.
INTRODUÇÃO
Diferente dos tipos de referência os tipos de valor não são alocados na memória heap, não são referenciados e não sofrem coleta de lixo. Até aqui está claro que um tipo valor, quando falamos em desempenho, é melhor que um tipo-referência. Então porque não utilizamos mais tipos de valor? Existem várias respostas para essa pergunta, mas, em minha opinião, o principal fator é a facilidade de se trabalhar com classes.
Já sabemos como funciona a conversão entre um tipo de referência para outro tipo referência e de um tipo-valor para outro tipo-valor. Agora vamos entender como o framework se comporta na conversão de um tipo valor para um tipo-referência. Esse tipo de conversão é chamado de Boxing.
BOXING DE TIPOS-VALOR
É comum declararmos uma variável de tipo valor e em algum momento precisar obter uma referência da instancia criada desse tipo. Irei mostrar um exemplo passo a passo para ficar fácil o entendimento. Veja o código abaixo:
C#
[sourcecode language="csharp"]
public class MinhaClasse
{
//declarando uma struct
//struct é um tipo valor
struct ExemploStruct
{
public int a, b;
}
void Main()
{
//declarando um objeto ArrayList
//esse objeto se encontra no namespace System.Collections
ArrayList Aux = new ArrayList();
//declarando uma variavel do tipo ExemploStruct
//Como esse tipo é uma struct
//seu valor será guardado na memória stack
ExemploStruct Ex;
}
}
[/sourcecode]
No código acima foi criada a classe MinhaClasse e dentro da classe foi criado um tipo struct chamado ExemploStruct e um método void, por enquanto você só precisa saber que void é um tipo de método que não tem retorno, chamando Main. O tipo struct é um tipo valor que é tipicamente usado para encapsular pequenos grupos de variáveis, como por exemplo, coordenadas ou características de um retângulo. Dentro de ExemploStruct foram criadas duas variáveis do tipo System.Int32, “a” e “b”. No método Main() foi criado um objeto do tipo ArrayList e logo abaixo declarado uma variável do tipo ExemploStruct. O tipo ArrayList está presente dentro do namespace System.Collections. Com esse tipo é possível se trabalhar com lista, sendo que, seu tamanho pode ser aumentando de acordo com a necessidade. O ArrayList possui alguns métodos e um deles é muito usado, o Add. O método Add adiciona um objeto no final do ArrayList. Veja agora o mesmo código com mais um trecho implementado, usando o método Add:
C#
[sourcecode language="csharp"]
public class MinhaClasse
{
//declarando uma struct
//struct é um tipo valor
struct ExemploStruct
{
public int a, b;
}
void Main()
{
//declarando um objeto ArrayList
//esse objeto se encontra no namespace System.Collections
ArrayList Aux = new ArrayList();
//declarando uma variavel do tipo ExemploStruct
//Como esse tipo é uma struct
//seu valor será guardado na memória stack
ExemploStruct Ex;
for (int i = 0; i < 5; i++)
{
Ex.a = 1; //Atribuindo valor a variavel a do tipo ExemploStruct
Ex.b = 2; //Atribuindo valor b variavel a do tipo ExemploStruct
Aux.Add(Ex);
}
}
[/sourcecode]
Veja que foi criado um laço de repetição usando um for. Nesse laço eu inicializado as variáveis do tipo ExemploStruct e uso o método Add do meu objeto ArrayList para adicionar a instancia de ExemploStruct dentro de sua lista. Todo loop que ocorrer dentro desse for uma nova instancia de ExemploStruct será criada e adicionada dentro do ArrayList. Lembra quando eu disse quando que o método Add do tipo ArrayList adiciona um objeto no final da lista? Lembram também que um objeto é uma referência (ponteiro) que aponta para o local onde está armazenado seus valores na memória heap? Ou seja, para que o método Add funcione vamos ter que converter o tipo ExemploStruct em um objeto, essa conversão é chamada de boxing. Mas, só precisamos fazer essa conversão explicitamente em algumas linguagens, como o C++. O compilador do C# faz isso automaticamente!
Lembrando que, para se trabalhar com objetos, mais recursos de processamento são usados como foi explicado no início desse post. Tranquilo o boxing né? Vejamos agora o Unboxing.
UNBOXING DE TIPOS VALOR
Ainda analisando o código usado como exemplo para entendermos o boxing, imagine que em um momento da aplicação seja necessário obter um determinado valor do ArrayList, como isso seria feito? Veja o exemplo abaixo:
C#
[sourcecode language="csharp"]
//Declarando um tipo valor ExemploStruct
ExemploStruct ExUnboxing;
/*Atribuindo o primeiro valor do ArrayList para a variavel ExUnboxing
usando casting*/
ExUnboxing = (ExemploStruct) Aux[0];
[/sourcecode]
Neste exemplo estou pegando o ponteiro contido no objeto do primeiro elemento do ArrayList e tentando coloca-lo na variável de tipo valor ExUnboxing. Para isso funcionar o CLR realizará dois passo.
1. Obter o endereço do objeto (boxed) na memória heap, esse primeiro passo é chamado do unboxing.
2. Os valores armazenados na memória heap são copiados para a instancia criada de tipo valor armazenada na memória stack.
Se juntarmos esses dois passos realizados a operação de unboxing se torna exatamente o oposto de boxing, entretanto, não se confunda, pois, o processo denominado unboxing é somente o primeiro.
Reforçando o que eu já disse, as operações realizadas no boxing e unboxing podem causar uma queda de desempenho na aplicação. Deve-se tomar cuidado com o casting realizado no unboxing para que exceções não sejam disparadas caso o objeto contido no elemento do ArrayList seja nulo ou de um tipo diferente do tipo que o receberá.
CONCLUSÃO
Em alguns momentos pode ser necessário realizar o boxing de um tipo valor para poder utilizar um método que requer um tipo referência. Eu mostrei um exemplo com essa publicação, mas, não quer dizer que seja o único.
Espero que esse conteúdo seja útil para alguém.
Até o próximo post!
REFERÊNCIAS
struct (C# Reference) - http://msdn.microsoft.com/en-us/library/ah19swz4.aspx
Classe ArrayList - http://msdn.microsoft.com/pt-br/library/system.collections.arraylist(v=vs.110).aspx
Programação aplicada com Microsoft .Net Framework – Jeffrey Richter