C#: Variáveis e tipos de dados
Pense em uma variável como uma caixa rotulada: a etiqueta é o nome, e a caixa contém os dados. Escolher o tamanho e o tipo certos de caixa mantém seus dados seguros e garante a eficiência.
1. Declaração e inicialização de variáveis
C# é uma linguagem fortemente tipada; portanto, é necessário especificar um tipo ao declarar uma variável (ou usar var para que o compilador o infira):
int age;
age = 25;
string name = "Alice";
double score = 95.5;
Você também pode declarar várias variáveis do mesmo tipo em uma única linha:
int x = 1, y = 2, z = 3;
Aviso: o C# não permite o uso de variáveis locais não inicializadas; o compilador gerará um erro.
2. Regras de nomenclatura
O C# impõe regras rígidas para a nomenclatura de variáveis:
- Deve começar com uma letra ou
_; não pode começar com um algarismo - Só pode conter letras, dígitos e
_ - Distingue maiúsculas de minúsculas (
ageeAgesão variáveis diferentes) - Não é permitido usar palavras-chave do C# (como
int,class,return)
(1) camelCase e PascalCase
O C# possui duas convenções de nomenclatura principais:
| Tipo de identificador | Estilo | Exemplos |
|---|---|---|
| Variáveis locais, campos | camelCase | studentName, totalCount |
| Métodos, classes, propriedades | PascalCase | CalculateSum, Student |
Dica: camelCase: a primeira palavra em minúscula, as palavras seguintes com a primeira letra maiúscula; PascalCase: todas as palavras com a primeira letra maiúscula.
int studentAge = 18;
double averageScore = 87.5;
string homeAddress = "Beijing";
3. Tipos de inteiros
O C# oferece 8 tipos de inteiros, abrangendo tanto os assinados quanto os não assinados:
| Tipo | Bytes | Intervalo | Sufixo |
|---|---|---|---|
sbyte |
1 | -128 ~ 127 | — |
byte |
1 | 0 ~ 255 | — |
short |
2 | -32.768 ~ 32.767 | — |
ushort |
2 | 0 ~ 65.535 | — |
int |
4 | -2.147.483.648 ~ 2.147.483.647 | — |
uint |
4 | 0 ~ 4.294.967.295 | U |
long |
8 | -9.223.372.036.854.775.808 ~ 9.223.372.036.854.775.807 | L |
ulong |
8 | 0 ~ 18.446.744.073.709.551.615 | UL |
Dica: Ao contrário do Java, o C# possui tipos de inteiros sem sinal (byte, ushort, uint, ulong). Observe que o byte do C# é sem sinal, enquanto a versão com sinal é sbyte.
▶ Exemplo
sbyte sb = -100;
byte b = 200;
short s = -30000;
ushort us = 60000;
int i = 100000;
uint ui = 3000000000U;
long l = 9000000000000000000L;
ulong ul = 18000000000000000000UL;
Console.WriteLine($"sbyte: {sb}");
Console.WriteLine($"byte: {b}");
Console.WriteLine($"short: {s}");
Console.WriteLine($"ushort: {us}");
Console.WriteLine($"int: {i}");
Console.WriteLine($"uint: {ui}");
Console.WriteLine($"long: {l}");
Console.WriteLine($"ulong: {ul}");
sbyte: -100
byte: 200
short: -30000
ushort: 60000
int: 100000
uint: 3000000000
long: 9000000000000000000
ulong: 18000000000000000000
4. Tipos de ponto flutuante
| Tipo | Bytes | Precisão | Intervalo (aprox.) | Sufixo | Caso de uso |
|---|---|---|---|---|---|
float |
4 | 7 dígitos | +/-1,5×10⁻⁴⁵ ~ +/-3,4×10³⁸ | f |
Gráficos, jogos |
double |
8 | 15-16 dígitos | +/-5,0×10⁻³²⁴ ~ +/-1,7×10³⁰⁸ | d (padrão) |
Computação científica |
decimal |
16 | 28-29 dígitos | +/-1,0×10⁻²⁸ ~ +/-7,9×10²⁸ | m |
Valores financeiros |
Aviso: Os literais decimais são double por padrão. É necessário adicionar um sufixo ao atribuir valores a float ou decimal; caso contrário, o compilador gerará um erro.
float f = 3.14f;
double d = 3.14;
decimal m = 3.14m;
Console.WriteLine($"float: {f}");
Console.WriteLine($"double: {d}");
Console.WriteLine($"decimal: {m}");
float: 3.14
double: 3.14
decimal: 3.14
Dica: decimal foi projetado para cálculos financeiros e evita erros de ponto flutuante binário. Por exemplo, 0.1 + 0.2 não é exatamente igual a 0.3 quando comparado a double, mas é exatamente igual a decimal.
5. Tipo bool
bool possui apenas dois valores: true e false, ocupando 1 byte.
Aviso: Ao contrário do C, o bool do C# não pode ser convertido implicitamente para ou a partir de inteiros. if(1) é inválido; você deve escrever if(true) ou if(x != 0).
bool isReady = true;
bool isEmpty = false;
Console.WriteLine($"isReady: {isReady}");
Console.WriteLine($"isEmpty: {isEmpty}");
isReady: True
isEmpty: False
6. Tipo char
O char do C# é um caractere Unicode de 2 bytes, e não um caractere ASCII de 1 byte como no C.
char ch1 = 'A';
char ch2 = '\u03a9';
Console.WriteLine($"ch1: {ch1}");
Console.WriteLine($"ch2: {ch2}");
Console.WriteLine($"ch1 code: {(int)ch1}");
Console.WriteLine($"ch2 code: {(int)ch2}");
ch1: A
ch2: Ω
ch1 code: 65
ch2 code: 937
Dica: char usa aspas simples 'A', enquanto string usa aspas duplas "A" — são tipos completamente diferentes.
7. Tipo string
string é um tipo de referência que representa uma sequência imutável de caracteres Unicode.
string greeting = "Hello";
string name = "World";
string message = greeting + ", " + name + "!";
Console.WriteLine(message);
Console.WriteLine($"Length: {message.Length}");
Hello, World!
Length: 13
Aviso: string é um tipo de referência, e seu valor padrão é null (não uma string vazia ""). Acessar uma string null resultará em uma exceção NullReferenceException.
8. Tipo implícito em var
O C# 3.0 introduziu a palavra-chave var, que permite que o compilador infira o tipo a partir do valor inicial:
var count = 42;
var price = 9.99m;
var label = "hello";
var flag = true;
Console.WriteLine(count.GetType().Name);
Console.WriteLine(price.GetType().Name);
Console.WriteLine(label.GetType().Name);
Console.WriteLine(flag.GetType().Name);
Int32
Decimal
String
Boolean
Atenção: var não significa “qualquer tipo” — o tipo da variável é determinado em tempo de compilação e deve ser inicializado. O seguinte é inválido:
var x;
var x = null;
Dica: Use var quando os nomes dos tipos forem longos ou quando o tipo for óbvio pelo contexto. Evite usá-lo em excesso, pois isso pode reduzir a legibilidade.
9. sizeof — Verificação do tamanho do tipo
sizeof retorna o número de bytes que um tipo ocupa. Pode ser usada diretamente para tipos primitivos; outros tipos exigem um contexto unsafe.
▶ Exemplo
Console.WriteLine($"sbyte: {sizeof(sbyte)} bytes");
Console.WriteLine($"byte: {sizeof(byte)} bytes");
Console.WriteLine($"short: {sizeof(short)} bytes");
Console.WriteLine($"ushort: {sizeof(ushort)} bytes");
Console.WriteLine($"int: {sizeof(int)} bytes");
Console.WriteLine($"uint: {sizeof(uint)} bytes");
Console.WriteLine($"long: {sizeof(long)} bytes");
Console.WriteLine($"ulong: {sizeof(ulong)} bytes");
Console.WriteLine($"float: {sizeof(float)} bytes");
Console.WriteLine($"double: {sizeof(double)} bytes");
Console.WriteLine($"decimal: {sizeof(decimal)} bytes");
Console.WriteLine($"char: {sizeof(char)} bytes");
Console.WriteLine($"bool: {sizeof(bool)} bytes");
sbyte: 1 bytes
byte: 1 bytes
short: 2 bytes
ushort: 2 bytes
int: 4 bytes
uint: 4 bytes
long: 8 bytes
ulong: 8 bytes
float: 4 bytes
double: 8 bytes
decimal: 16 bytes
char: 2 bytes
bool: 1 bytes
10. const Constantes
Use const para declarar constantes em tempo de compilação cujos valores não podem ser alterados. Elas devem ser inicializadas no momento da declaração:
const double Pi = 3.14159265358979;
const int MaxRetry = 3;
const string AppName = "MyApp";
Console.WriteLine($"Pi = {Pi}");
Console.WriteLine($"MaxRetry = {MaxRetry}");
Console.WriteLine($"AppName = {AppName}");
Pi = 3.14159265358979
MaxRetry = 3
AppName = MyApp
Aviso: os nomes const geralmente utilizam o formato PascalCase. O valor deve ser determinável em tempo de compilação e não pode ser uma variável nem o resultado de uma chamada de método.
Dica: Se você precisar de uma “constante” determinada em tempo de execução, use um campo readonly em vez disso.
11. Valores padrão de tipos
Cada tipo possui um valor padrão quando nenhum valor inicial é atribuído:
| Tipo | Valor padrão |
|---|---|
sbyte / byte / short / ushort / int / uint / long / ulong |
0 |
float |
0.0f |
double |
0.0d |
decimal |
0.0m |
char |
'\0' |
bool |
false |
string |
null |
| Qualquer tipo de referência | null |
▶ Exemplo
int defaultInt = default;
bool defaultBool = default;
char defaultChar = default;
string defaultString = default;
double defaultDouble = default;
Console.WriteLine($"int: [{defaultInt}]");
Console.WriteLine($"bool: [{defaultBool}]");
Console.WriteLine($"char: [{(int)defaultChar}]");
Console.WriteLine($"string: [{defaultString}]");
Console.WriteLine($"double: [{defaultDouble}]");
int: [0]
bool: [False]
char: [0]
string: []
double: [0]
Dica: A palavra-chave default permite obter o valor padrão de qualquer tipo e é especialmente comum em genéricos: default(T).
12. Tipos de valor x tipos de referência — Introdução
Os tipos do C# se enquadram em duas grandes categorias:
| Categoria | Armazenamento | Comportamento de atribuição | Tipos típicos |
|---|---|---|---|
| Tipo de valor | Pilha (normalmente) | Copia o valor | int, bool, char, decimal, struct, enum |
| Tipo de referência | Heap | Copia a referência (endereço) | string, class, object, matrizes |
int a = 10;
int b = a;
b = 20;
Console.WriteLine($"a = {a}, b = {b}");
string s1 = "hello";
string s2 = s1;
s2 = "world";
Console.WriteLine($"s1 = {s1}, s2 = {s2}");
a = 10, b = 20
s1 = hello, s2 = world
Aviso: s1 não se tornou "world" porque string é imutável — s2 = "world" não modifica o objeto original, mas faz com que s2 aponte para um novo. A atribuição de tipos de valor copia o valor real, enquanto a atribuição de tipos de referência copia a referência. No entanto, a imutabilidade de string faz com que ele se comporte como um tipo de valor.
❓ Perguntas Frequentes
P: Qual é a diferença entre
varedynamic? R:vardetermina o tipo em tempo de compilação e é seguro em termos de tipos;dynamicdetermina o tipo em tempo de execução, não possui verificação de tipo em tempo de compilação, apresenta desempenho inferior e é mais propenso a erros.
P: Por que
decimalé melhor do quedoublepara cálculos monetários? R:decimalutiliza armazenamento decimal, de modo que0.1pode ser representado com exatidão;doubleusa armazenamento binário, no qual0.1não pode ser representado com exatidão, o que leva a erros cumulativos de arredondamento.
P:
stringé um tipo de valor ou um tipo de referência? R:stringé um tipo de referência, mas, devido à sua imutabilidade, a atribuição apresenta semântica de valor — a modificação de uma variável não afeta a outra.
P: Qual é a diferença entre
constereadonly? R:consté uma constante de tempo de compilação que deve ser atribuída na declaração e é implicitamente estática;readonlyé uma constante de tempo de execução que pode ser atribuída em um construtor e pode variar de instância para instância.
📖 Resumo
- O C# é uma linguagem fortemente tipada; as variáveis devem ter seu tipo declarado ou usar
varpara inferência - As variáveis locais usam camelCase; os métodos e as classes usam PascalCase
- Existem 8 tipos de inteiros (incluindo os sem sinal);
inté o mais utilizado - Use
decimalpara transações financeiras,doublepara computação científica efloatpara gráficos boolnão pode ser convertido implicitamente para ou de inteiros;charé um tipo Unicode de 2 bytesvarrequer inicialização, e o tipo é determinado em tempo de compilaçãoconstdefine constantes em tempo de compilação (PascalCase);readonlydefine constantes em tempo de execução- A palavra-chave
defaultobtém o valor padrão de qualquer tipo - A atribuição de tipos de valor copia o valor; a atribuição de tipos de referência copia a referência
📝 Exercícios
- Declare uma variável
intchamadaagecom o valor da sua idade e uma variávelstringchamadanamecom o valor do seu nome; em seguida, exiba ambas - Calcule
0.1 + 0.2utilizandofloat,doubleedecimal, respectivamente, e verifique se os resultados são exatamente iguais a0.3 - Use
sizeofpara imprimir os tamanhos em bytes deint,double,charebool - Declare uma variável
const double Pi = 3.14159265e calcule a área de um círculo de raio 5; em seguida, exiba o resultado - Use a palavra-chave
defaultpara obter e exibir os valores padrão deint,bool,charestring