1. Tipos por valor vs. tipos por referência
Em JavaScript, praticamente tudo que não é primitivo é um objeto acessado por referência, e você raramente precisa pensar nisso. Em C#, essa distinção é explícita e afeta como uma variável se comporta quando é copiada ou passada para um método.
Tipos por valor (struct) | Tipos por referência (class) | |
|---|---|---|
| Onde vivem | Stack (normalmente) | Heap |
Ao atribuir b = a | Copia o valor inteiro — dois independentes | Copia a referência — os dois apontam para o mesmo objeto |
| Exemplos | int, double, bool, char, struct customizado | string, class customizada, arrays, coleções |
Fig. 1 — Copiar uma variável de tipo valor duplica o dado; copiar uma de tipo referência duplica só o "endereço".
int a = 10;
int b = a;
b++;
Console.WriteLine(a); // 10 — a não foi afetado
var cliente1 = new Cliente { Nome = "Ana" };
var cliente2 = cliente1;
cliente2.Nome = "Bruno";
Console.WriteLine(cliente1.Nome); // "Bruno" — mesmo objeto!
Esse é o erro mais comum de quem vem de linguagens dinâmicas: assumir que toda atribuição
"copia". Para tipos por referência, cliente2 = cliente1 não cria um
novo cliente — cria uma segunda etiqueta apontando para o mesmo objeto na memória.
2. Tipos primitivos essenciais
| Tipo | Tamanho | Uso típico |
|---|---|---|
int | 32 bits | Contadores, Ids, quantidades |
long | 64 bits | Números muito grandes (Ids de sistemas distribuídos, timestamps) |
double | 64 bits, ponto flutuante | Cálculos científicos — não dinheiro |
decimal | 128 bits, precisão exata | Dinheiro e qualquer valor financeiro |
bool | — | Verdadeiro/falso |
char | 16 bits (UTF-16) | Um único caractere |
string | referência | Texto — imutável, como em JS |
double representa números em binário, o que significa que valores
decimais "redondos" como 0.1 não têm representação exata — o mesmo problema de arredondamento
que existe em 0.1 + 0.2 no JavaScript. decimal
usa uma representação de base 10 internamente, exata para valores monetários. Já que este curso
trabalha pesado com SQL Server: decimal do C# corresponde exatamente
ao tipo DECIMAL/NUMERIC do T-SQL — use os
dois juntos sempre que o dado envolver dinheiro.
3. Nullable value types
Tipos por valor normalmente não podem ser null — um
int sempre tem algum número. Para representar "ausência de
valor" (o mesmo conceito de NULL no SQL Server), C# tem os tipos
anuláveis, marcados com ?:
int? idade = null; // válido — int normal não aceitaria null
idade = 30;
if (idade.HasValue)
Console.WriteLine(idade.Value);
// forma mais idiomática
Console.WriteLine(idade ?? 0); // usa 0 se idade for null
Uma coluna INT NULL no SQL Server mapeia naturalmente para
int? em C#; uma coluna INT NOT NULL mapeia
para int puro. Essa correspondência vai reaparecer o tempo todo a
partir do módulo de integração com Entity Framework.
4. Operadores essenciais
| Operador | Nome | Exemplo |
|---|---|---|
?? | Null-coalescing | nome ?? "sem nome" |
??= | Atribuição null-coalescing | nome ??= "sem nome" |
?. | Null-conditional | cliente?.Nome (não lança exceção se cliente for null) |
is | Checagem/padrão de tipo | if (obj is Cliente c) |
&& / || | E / OU lógico com curto-circuito | Idêntico ao JS |
Cliente? cliente = ObterClienteOuNull();
// sem null-conditional: precisaria de um if aninhado
string cidade = cliente?.Endereco?.Cidade ?? "Cidade não informada";
5. Conversões de tipo
C# distingue conversões implícitas (seguras, sem perda de dado, o compilador faz sozinho) de explícitas (potencialmente perdem dado, exigem um cast escrito por você):
int inteiro = 10;
double implicita = inteiro; // OK sem cast — int cabe em double sem perda
double valor = 9.99;
int explicita = (int)valor; // precisa de cast — trunca para 9, perde o .99
string texto = "42";
int convertido = int.Parse(texto); // lança exceção se o texto não for válido
bool ok = int.TryParse(texto, out int numero); // não lança — devolve true/false
Prefira sempre TryParse a Parse quando o
texto vem de uma fonte não confiável (entrada do usuário, um campo de formulário) — evita que uma
entrada inválida derrube a aplicação com uma exceção não tratada.
6. const vs. readonly
const | readonly | |
|---|---|---|
| Quando o valor é fixado | Em tempo de compilação | Em tempo de execução (no construtor, por exemplo) |
| Pode depender de cálculo/parâmetro? | Não — precisa ser um literal | Sim |
| Exemplo | const double Pi = 3.14159; | readonly DateTime CriadoEm = DateTime.Now; |
7. Onde isso te leva
Entender valor vs. referência agora evita bugs sutis mais adiante — principalmente quando você começar a passar objetos para métodos (próximo capítulo) e, mais tarde, quando estruturas de dados inteiras trafegarem entre C# e SQL Server.