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.
Tipo | Descrição |
byte | Inteiro de 8 bits (0 a 255). |
sbyte | Inteiro de 8 bits (-127 a 128). |
ushort | Inteiro de 16 bits (0 a 65 535). |
short | Inteiro de 16 bits (-32 768 a 32 767). |
uint | Inteiro de 32 bits (0 a 4 294 967 295). |
int | Inteiro de 32 bits (-2 147 483 648 a 2 147 483 647). |
ulong | Inteiro de 64 bits (0 a 18 446 744 073 709 551 615). |
long | Inteiro de 64 bits (-9 223 372 036 854 775 808 a 9 223 372 036 854 775 807). |
double | ponto flutuante binário 8 bytes (±5.0×10-324 a ±1.7×10308). |
float | Ponto flutuante binário 4 bytes (±1.5×10-45 a ±3.4×1038). |
decimal | Ponto flutuante decimal de 128 bits. (1.0×10-28 a 7.9×1028). |
bool | Pode ter os valores true e false. |
char | Um ú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.
Alias | Nome original do tipo |
bool | Boolean |
byte | Byte |
sbyte | Sbyte |
char | Char |
decimal | Decimal |
double | Double |
Float | Single |
Int | Int32 |
Uint | UInt32 |
Long | Int64 |
Ulong | UInt64 |
object | Object |
short | Int16 |
ushort | UInt16 |
string | String |
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.