Toda linguagem de programação possui tipos de dados, isso é primordial para qualquer linguagem fortemente “tipada” como é o caso do C#.

O .Net divide os tipos de dados em categorias:

  • ValueType (Tipos por Valor)
  • ReferenceType (Tipos por Referência)

ValueTypes no .NET Framework

Os tipos por valor no .NET Framework são variáveis baseadas diretamente em valores. A afirmação parece redundante, mas é necessário fixar o conceito do tipo por valor para facilitar o entendimento do outro tipo, o ReferenceType.

Listagem 1: Exemplar de tipos por valor

using System;
namespace Types
{
    class Program
    {
        static void Main(string[] args)
        {
            int Val1 = 10;
            int val2 = Val1;
            Console.WriteLine(val2);
        }
    }
}

Quando é realizada uma simples operação onde se iguala duas variáveis do tipo valor, a variável atribuidora é copiada, passando a existir duas variáveis em memória com o mesmo valor. Variáveis desse tipo herdam implicitamente da classe System.ValueType.

Observação: Os tipos existentes em tipos por valor possuem um limite de dados que ao ultrapassar esse valor, acarretará em exceção de overflow.

TipoDescrição
byteInteiro de 8 bits (0 a 255).
sbyteInteiro de 8 bits (-127 a 128).
ushortInteiro de 16 bits (0 a 65 535).
shortInteiro de 16 bits (-32 768 a 32 767).
uintInteiro de 32 bits (0 a 4 294 967 295).
intInteiro de 32 bits (-2 147 483 648 a 2 147 483 647).
ulongInteiro de 64 bits (0 a 18 446 744 073 709 551 615).
longInteiro de 64 bits (-9 223 372 036 854 775 808 a 9 223 372 036 854 775 807).
doubleponto flutuante binário 8 bytes (±5.0×10-324 a ±1.7×10308).
floatPonto flutuante binário 4 bytes (±1.5×10-45 a ±3.4×1038).
decimalPonto flutuante decimal de 128 bits. (1.0×10-28 a 7.9×1028).
boolPode ter os valores true e false.
charUm único caractere Unicode de 16 bits.

Uma variável ValueType não recebe o operador “new” obrigatoriamente (mas ela possuí um construtor). Todos elas são uma struct, para consumir menor espaço lógico em memória.

Dentro do ValueType existem três subcategorias que são:

  • Built-In Type (Tipos Internos)
  • User Defined Types (Struct)
  • Enumeradores (Enum)

Built-In Type

Os tipos internos são na verdade alias (apelidos) que encurtam os nomes para as chamadas das variáveis do tipo ValueType.

AliasNome original do tipo
boolBoolean
byteByte
sbyteSbyte
charChar
decimalDecimal
doubleDouble
FloatSingle
IntInt32
UintUInt32
LongInt64
UlongUInt64
objectObject
shortInt16
ushortUInt16
stringString

Os apelidos nada mais são que a chamada implícita para os structs responsáveis, portanto não há diferença técnica entre elas, mas sim a diferença semântica.

User Defined Types

O struct no .NET Frameworké geralmente utilizado para agrupar pequenas quantidades de variáveis relacionadas e realizar pequenos procedimentos. É possível criar construtor, variáveis Constante, propriedades, métodos, eventos.

Listagem 2: Exemplar de um Struct

using System;
namespace Types
{
    class Program
    {
        static void Main(string[] args)
        {
            new Circulo { Raio = 20 }.CalcularRaio();
        }
    }
    public struct Circulo
    {
       public int Raio;
        public int CalcularRaio()
        {
            return (int)(Math.PI * Math.Pow(Raio, 2));
        }
    }
}

Enumeradores no .NET Framework

O enum é utilizado para geração de listas com valores constantes e distintos entre si.

Por padrão, sempre o primeiro valor da lista é zero e o incremento do valor segue nos demais itens da lista. Caso opte por um valor diferente para o primeiro item não é necessário informar os demais, o incremento ocorre da mesma forma, só que a partir do número deixado.

Listagem 3: Exemplar de um Enum

    enum SouthAmerica
    {
        Brasil=1,
        Argentina,
        Chile,
        Colombia,
        Equador,
        Uruguai
    } 

Reference Types no .NET Framework

Os tipos por referência possuem algumas diferenças quanto ao seu gerenciamento em memória, inicialização e forma de armazenamento.

Os tipos de referências quando armazenados em memória são alocados em um heap e ficando na mira do Garbage Collection, quando a referência não estiver mais em uso, este faz a limpeza das informações da memória.

Todos os ReferenceType necessitam do operador new, conhecido por todos para gerar uma nova instância de um objeto. Quando o operador é executado é criado o objeto na memória e esse objeto possui uma referência, como se fosse um ponteiro, e o conteúdo fica na memória.

Diferente do ValueType, o ReferenceType aceita valores nulos, entretanto o null, indicará uma exceção de código, indicando que o mesmo ainda não tem uma referência criada em memória (entrando na jogada o new).

Os tipos de referências

Tipo
Class
Delegate
Dynamic
Interface
Object
String
Array

Listagem 4: Exemplar de um Tipo por Referência

static void Main(string[] args)
{
  Carro objCarro = new Carro { ano = 10, cor = "Vermelho", modelo = "Bla" };
}

public class Carro
{
  public string cor { get; set; }
  public int ano { get; set; }
  public string modelo { get; set; }
}

O String no .NET Framework

O string no .NET Framework< é considerado um tipo por referência, mas possui referências de sintaxe do tipo por valor. O string não obrigatoriamente precisa ser iniciado por new.

Quando é realizada uma comparação entre strings, nela são comparados os valores e não sua referência.

Tipos Dinâmicos

Dentro do raciocínio exposto, um dynamic faz parte da categoria de tipos por referência, porém ele é um tipo que é apenas checado em momento de execução, feita para atender a interoperabilidade com linguagens dinâmicas, facilitando alguns processos específicos no desenvolvimento.

Para o exemplo de dynamic, foi incluída a classe ExpandoObject(), servindo de auxiliar para o proposto.

Listagem 5: Exemplar de um dynamic com ExpandoObject

        public void Dinamico()
        {
            dynamic runTime = new ExpandoObject();
            runTime.Nome = "Robson Alves";
            runTime.Idade = 23;
            runTime.Nasc = DateTime.Parse("07/02/1989");
            runTime.Weight = 93.2;
            Console.WriteLine("Nome: " + runTime.Nome);
        }

O exemplo acima demonstra uma variável totalmente dinâmica e criada em tempo de execução, mas no fundo o dynamic é um tipo object com tratamentos. Isso quer dizer que podemos passar um valor para o dynamic, e/ou qualquer tipo.

Listagem 6: Exemplar dynamic

        static void Main(string[] args)
        {
            int par1 = 0;
            for (int i = 0; i < 100; i++)
            {
                if (i % 2 == 0 && par1 == 0)
                    par1 = i;
                else
                    if (i % 2 == 0)
                    {
                        Console.WriteLine(SomarPares(par1, i));
                        par1 = 0;
                    }
            }
            Console.Read();
        }
        public static dynamic SomarPares(int par1, int par2)
        {
            return par1 + par2;
        }

Os exemplos de dynamic são bem simples, pois não é o foco desse artigo. O poder que esse tipo fornece é muito grande, mantendo certos cuidados, pois as exceções desse tipo só são vistas em tempo de execução e dependendo da sua aplicação isso pode ser custoso.

Conclusões

Entender tudo sobre cada tipo é legal, porém não é nada relevante decorar tudo isso. O foco principal está em saber o que cada um tem de melhor e assim trabalhar com de forma coerente e concisa.

Dúvida/Sugestão é só comentar!

Obrigado.