Conceitos .NET - Fundamentos sobre tipos de dados


Se você quer ser um desenvolvedor .NET que produza código robusto tem que compreender bem o conceito de tipos de dados usados pela plataforma .NET. Se você nem imagina o que são 'tipos primitivos' e não compreende a diferença entre 'tipos por referência' e 'tipos por valor' seu código vai estar sujeitos a bugs e com certeza não vai ter o desempenho esperado.

Tipos Primitivos

Os tipos de dados primitivos são os tipos de dados suportados diretamente pelo compilador. Os tipos primitivos são mapeados diretamente para os tipos que existem na livraria base de classes (base class library). Eles são identificados por palavras chaves que na verdade são um aliás para os tipos predefinidos no namespace System. Assim um int mapeia diretamente para o tipo System.Int32.

Por causa disto é que existe a equivalência nas declarações das linhas de código abaixo:

Visual Basic .NET

C#

Dim m As System.Int32 = New System.Int32(5)

Dim m As System.Int32 = 5

System.Int32 m = new System.Int32(5)

System.Int32 m = 5

Os tipos primitivos são diferentes dos tipos de estruturas pois eles possuem algumas características especiais como :

Os tipos primitivos definidos no VB .NET são :

Tipos de dados por Valor e por referência

Um tipo de dado e considerado tipo por valor se ele trata o dado dentro da sua própria alocação de memória. Já um tipo de dado por referência contêm um ponteiro para outra alocação de memória que gerencia o dado.

Os tipos por valor incluem:

  • Todos os tipos de dados numéricos.(Byte - Short - Int - Long - Single - Double - Decimal)
  • Boolean, Char, e Date
  • Todas as estruturas(struct) , mesmo se seus membros são tipos de referência.
  • A enumerações (Enum) desde que seus tipos correspondentes sejam sempre : Byte, Short, Integer, ou Long

Os tipos por referência incluem:

Observação : O tipo String possui as seguintes características especiais:

Nota : Você pode atribuir um tipo de valor ou tipo de referência para uma variável do tipo objeto . Uma variável do tipo objeto sempre possui um ponteiro para o dado nunca o próprio dado. Porém quando você atribui um tipo de valor para um variável objeto ela se comporta como se possuisse o próprio dado. Como saber então se uma variável objeto esta atuando por referência ou por valor ?

R : Para saber se uma variável objeto esta atuando como um tipo por referência ou por valor você pode usar o método IsReference da classe Information do namespace Microsoft.VisualBasic. Se Microsoft.VisualBasic.Information.IsReference retornar True o contéudo da variável objeto representa um valor por referência.

 Curiosidade: Em Java existem somente 8 tipos de dados primitivos : Boolean , Char , byte , short , int , long , float ,  double.

Tipos por Valor

As propriedades dos tipos de dados por valor são:

Tipos por referência

As propriedades dos tipos de dados por referência são:

  • São alocados em um heap e submetidos a coleta de lixo (garbage collector) quando não existir mais nenhuma referência ao dado.
  • A variável armazena apenas a referência ao dado , o dado sem si fica alocado no heap.
  • Sempre contém um valor do tipo ou uma referência Null.
  • Devem ser iniciados com o operador New.
  • Atribuir uma variável de referência a outra variável faz com que esta variável contenha uma cópia da referência não uma cópia do valor que esta sendo referenciado.
  • Uma referência Null refere-se a nada ; é inválido fazer algo com uma referência Null exceto atribuí-la. Uma variável de referência pode conter um Null mas não podemos usar a variável com o valor Null.
  • São usados para tipos de tamanho grande ( maior que 16 bytes).

Nota: as passagens de parâmetro no .NET são por padrão por  valor, ao contrario das versões anteriores do vb que eram por referência.

Vamos a um exemplo prático para mostrar a diferença.

Exemplo:

O código acima produz o seguinte resultado:

Declaramos duas variáveis locais do tipo Integer por valor : valor1 e valor2 e duas variáveis do tipo por referência : referencia1 e referencia2

Como as variáveis do tipo por valor tem sua própria área de alocação a atribuição que foi feita para a variável valor2 em : Dim valor2 as Integer = valor1 não impacta a variável local valor1. Assim valor1 possuirá o valor 0 e valor2 o valor 123 atribuído.

Quando eu declaro Dim referencia2 As Class1 = referencia1  as duas variáveis irão apontar para a mesma referência e irão exibir o mesmo valor atribuído a referencia2.

Lembre-se : Quando você atribui uma variável do tipo por valor a outra variável do tipo por valor uma cópia do valor é feita. Já qando você faz o mesmo como variáveis do tipo por referência somente o endereço de memória é copiado.

Considerações

Quando um objeto é alocado de um heap o operador New retorna o endereço de  memória do objeto e você armazena este valor em uma variável. A esta variável chamamos variável do tipo por referência pois a variável não contém o objeto e sim uma referência ao objeto. Isto nos leva a considerar que:

  • O processo acima faz com que a memória precise ser alocada do heap , o que pode forçar a uma ocorrência de coleta de lixo.
  • Os tipos por referência são sempre acessados através de seus ponteiros , assim , cada vez que seu código faz referência a qualquer membro de um objeto na heap , código precisa ser gerado e executado para desfazer a referência ao ponteiro afim de obter a ação desejada. Isto afeta o tamanho e a velocidade de sua aplicação.

Objetos do tipo por valor não podem se alocados na heap e a variável representando o objeto não contém um ponteiro para um objeto e sim o próprio objeto. Desta forma não há a necessidade de desfazer referência alguma e o desempenho é maior.

Sempre que possível você deve preferir usar tipos variáveis por valor a por referência. Geralmente isto é possível nas seguintes condições:

  • O tipo de variável atua como um tipo primitivo.
  • O tipo de variável não precisa herdar de qualquer outro tipo.
  • O tipo de variável não terá qualquer outro tipo derivado dele.
  • Objetos do tipo não serão passados com frequência como métodos com argumentos.

A principal vantagem em usar variáveis de tipo por valor é que elas não serão alocadas no heap. No entanto existem muitas limitações inerentes a variáveis do tipo por valor quando comparadas as do tipo por referência que você deverá considerar quando decidir utilizá-las.

Boxing e Unboxing

Para terminar vou mencionar a existência do processo boxing e unboxing sem entrar em detalhes pois isto merece um artigo à parte.

Existem situações quando é conveniente tratar um valor por tipo como sendo um valor por referência.Quando isto ocorre você tem uma saída...

  • A conversão de uma instância de um tipo por valor em um objeto o qual implica que a instância irá carregar a informação e será alocada na memória é chamada boxing. A instrução box converte um valor do tipo por valor em um objeto fazendo uma cópia do tipo por valor e embutindo-o em um novo objeto alocado.
  • o processo inverso ou seja a conversão de uma instância de um objeto em um tipo por valor é chamada unboxing.

E vou ficando por aqui. Até o próximo artigo sobre conceitos .NET...