C# Tipos de Dados
Na aula Variáveis você criou caixas com nome para guardar valores. Mas cada caixa do C# só aceita um tipo de valor: uma guarda números inteiros, outra guarda números com vírgula, outra guarda texto. Esse "tipo" é o tipo de dado. Nesta aula você vai conhecer os tipos que vai usar todos os dias, ver o que cada um guarda e entender por que o compilador reclama quando você tenta pôr um texto numa caixa de número.
- Os seis tipos do dia a dia:
int,double,decimal,char,boolestring. - Qual tipo escolher para cada informação (idade, altura, preço, letra, sim/não, nome).
- Quantos bytes cada tipo ocupa, com
sizeof. - Que
inté um apelido deSystem.Int32, e como descobrir o tipo de um valor comGetType(). - O valor padrão de cada tipo (
default). - Os erros que aparecem quando o tipo não combina:
CS0029,CS0266eCS0165.
Todos os programas desta aula foram rodados com o .NET 10 (C# 14) na máquina fictícia da Ana (usuária ana, computador notebook, Ubuntu em português), na pasta ~/cs, com o comando dotnet run arquivo.cs (aula Rodar com dotnet run).
A ideia: potes para cada coisa
Na cozinha da Ana, cada coisa vai num recipiente próprio: o açúcar no pote, o leite na garrafa, os ovos na caixinha. Ninguém põe leite na caixinha de ovos: não cabe, e vazaria.
No C# é igual. Antes de guardar um valor, você diz que tipo de pote a variável é. Esse tipo decide três coisas:
- o que cabe nela (número inteiro, número com vírgula, texto…);
- quanto espaço ela ocupa na memória;
- o que dá para fazer com ela (somar dois números faz sentido; "somar" duas letras, nem tanto).
E o C# confere tudo isso antes de o programa rodar, na compilação. Por isso se diz que o C# é uma linguagem de tipagem estática e forte: o tipo de cada variável é decidido no código e nunca muda.
1. Os seis tipos do dia a dia
A ficha de cadastro da Ana na lojinha tem seis informações, e cada uma pede um tipo diferente:
int idade = 29; double altura = 1.65; decimal saldo = 1250.75m; char inicial = 'A'; bool cadastrada = true; string nome = "Ana"; Console.WriteLine(nome); Console.WriteLine(idade); Console.WriteLine(altura); Console.WriteLine(saldo); Console.WriteLine(inicial); Console.WriteLine(cadastrada);
$ dotnet run tipos.cs Ana 29 1,65 1250,75 A True
- int idade = 29;
intvem de integer, "inteiro": números sem vírgula, positivos ou negativos. É o tipo padrão para contar coisas: idade, quantidade, pontos. Aula Inteiros.- double altura = 1.65;
double("duplo", de "precisão dupla"): números com vírgula, para medidas como altura, peso e distância. No código, a vírgula se escreve com ponto:1.65. Aula float, double e decimal.- decimal saldo = 1250.75m;
decimal: números com vírgula exatos, feitos para dinheiro. Omno fim do número diz "este número édecimal" (de money, "dinheiro"). Sem ele, o C# acha que1250.75édouble.- char inicial = 'A';
charvem de character, "caractere": um caractere só, entre aspas simples. Aula char e bool.- bool cadastrada = true;
bool(de boolean, "booleano"): só dois valores,true(verdadeiro) efalse(falso). Serve para respostas de sim ou não.- string nome = "Ana";
string("cadeia", de letras): um texto de qualquer tamanho, entre aspas duplas. Aula Strings.
Repare em duas coisas na saída:
- No código você escreveu
1.65, com ponto, mas a saída mostra1,65, com vírgula. O código C# é sempre em "inglês" (ponto decimal), mas oConsole.WriteLinemostra os números do jeito do país do computador, e o Ubuntu da Ana está em português do Brasil. Isso se chama cultura e tem aula própria: Cultura (pt-BR × en-US). - O
truevirouTrue, com T maiúsculo. No código é sempre minúsculo; na hora de mostrar, o .NET escreveTrueeFalse(e não traduz para "Verdadeiro").
Qual tipo usar para cada informação
| A informação é… | Exemplo | Tipo | Valor no código |
|---|---|---|---|
| Uma contagem, sem vírgula | idade, quantidade, pontos | int | 29 |
| Uma medida, com vírgula | altura, peso, temperatura | double | 1.65 |
| Dinheiro | preço, saldo, salário | decimal | 19.90m |
| Uma letra ou símbolo | inicial, sexo na ficha, tecla | char | 'A' |
| Sim ou não | está logado? é maior de idade? | bool | true / false |
| Um texto | nome, e-mail, endereço | string | "Ana" |
Eles são feitos de dígitos, mas não são números: ninguém soma dois CEPs, e o zero da frente importa (01310-100). Guarde-os em string: string cep = "01310-100";.
Missão: o programa não compila: a caixa idade é int, mas recebeu um texto ("29", entre aspas). Clique em Rodar para ver o erro CS0029 e depois conserte, guardando o número 29, para mostrar Idade: 29.
int idade = "29";
Console.WriteLine("Idade: " + idade);
int idade = 29;
Console.WriteLine("Idade: " + idade);
O + entre "Idade: " e idade junta o texto com o número (veja Strings; a forma moderna, $"Idade: {idade}", está em Interpolação).
2. Cada tipo ocupa um espaço: sizeof
A memória do computador é medida em bytes. Cada tipo de número ocupa um número fixo deles, e o operador sizeof ("tamanho de") diz quantos:
Console.WriteLine($"bool: {sizeof(bool)} byte");
Console.WriteLine($"byte: {sizeof(byte)} byte");
Console.WriteLine($"char: {sizeof(char)} bytes");
Console.WriteLine($"short: {sizeof(short)} bytes");
Console.WriteLine($"int: {sizeof(int)} bytes");
Console.WriteLine($"long: {sizeof(long)} bytes");
Console.WriteLine($"float: {sizeof(float)} bytes");
Console.WriteLine($"double: {sizeof(double)} bytes");
Console.WriteLine($"decimal: {sizeof(decimal)} bytes");
$ dotnet run tamanhos.cs bool: 1 byte byte: 1 byte char: 2 bytes short: 2 bytes int: 4 bytes long: 8 bytes float: 4 bytes double: 8 bytes decimal: 16 bytes
- $"… {sizeof(int)} …"
- O
$antes das aspas permite pôr um valor dentro do texto, entre chaves. É a interpolação; aqui ela só serve para montar cada linha. - sizeof(int)
- Quantos bytes um
intocupa: 4. No C# esses tamanhos são fixos: uminttem 4 bytes no Linux, no Windows, no Mac, no celular e no editor do guia.
Quanto mais bytes, maiores (ou mais precisos) os números que cabem. Um byte vai só de 0 a 255; um long passa de 9 quintilhões. Os tipos byte, short, long e float aparecem nas próximas aulas. O string não está na lista porque não tem tamanho fixo: um texto pode ter 3 letras ou 3 milhões (sizeof(string) nem compila: CS0233, "string não tem um tamanho predefinido").
3. Palavra-chave e nome .NET: int = System.Int32
As palavras int, double, string etc. são apelidos que o C# dá a tipos que vêm do .NET. Cada uma tem um nome "completo". O método GetType() ("obter o tipo") mostra esse nome:
int idade = 29; double altura = 1.65; decimal saldo = 1250.75m; char inicial = 'A'; bool cadastrada = true; string nome = "Ana"; Console.WriteLine(idade.GetType()); Console.WriteLine(altura.GetType()); Console.WriteLine(saldo.GetType()); Console.WriteLine(inicial.GetType()); Console.WriteLine(cadastrada.GetType()); Console.WriteLine(nome.GetType());
$ dotnet run gettype.cs System.Int32 System.Double System.Decimal System.Char System.Boolean System.String
System é o "sobrenome" (o namespace, aula Namespaces e using), e Int32 quer dizer "inteiro de 32 bits" (4 bytes × 8 bits = 32). Escrever int ou Int32 dá exatamente o mesmo tipo:
int a = 10; System.Int32 b = 20; Int32 c = 30; Console.WriteLine(a + b + c); Console.WriteLine(typeof(int) == typeof(Int32));
$ dotnet run alias.cs 60 True
typeof(int) ("tipo de int") devolve o tipo em si, e o == compara os dois: True, são o mesmo. No dia a dia, use sempre a palavra-chave (int, string): é o que a Microsoft recomenda e o que você vai ver em quase todo código. O nome .NET aparece em mensagens de erro e em métodos como Int32.Parse (igual a int.Parse, aula Texto → Número).
A tabela completa
| Palavra-chave | Tipo .NET | Bytes | Guarda |
|---|---|---|---|
bool | System.Boolean | 1 | true ou false |
byte | System.Byte | 1 | inteiro de 0 a 255 |
sbyte | System.SByte | 1 | inteiro de -128 a 127 |
short | System.Int16 | 2 | inteiro de -32 768 a 32 767 |
ushort | System.UInt16 | 2 | inteiro de 0 a 65 535 |
int | System.Int32 | 4 | inteiro de uns -2,1 a 2,1 bilhões |
uint | System.UInt32 | 4 | inteiro de 0 a uns 4,2 bilhões |
long | System.Int64 | 8 | inteiro de uns -9,2 a 9,2 quintilhões |
ulong | System.UInt64 | 8 | inteiro de 0 a uns 18 quintilhões |
float | System.Single | 4 | número com vírgula, uns 7 dígitos certos |
double | System.Double | 8 | número com vírgula, uns 15 a 17 dígitos certos |
decimal | System.Decimal | 16 | número com vírgula exato, 28 a 29 dígitos |
char | System.Char | 2 | um caractere (UTF-16) |
string | System.String | varia | texto |
object | System.Object | varia | qualquer coisa (aula A Classe object) |
Os limites exatos de cada tipo estão em Tipos e Limites.
4. Tipos de valor e tipos de referência
Os tipos da tabela se dividem em duas famílias, e por enquanto basta saber os nomes:
- Tipos de valor:
int,double,decimal,char,boole os outros números. A caixa guarda o próprio valor. Copiar a variável copia o valor. - Tipos de referência:
string,object, os arrays e as classes que você vai criar. A caixa guarda o endereço de onde o valor está. Uma referência pode valernull("nada").
A diferença só começa a importar quando você criar seus próprios tipos, e é o assunto de Valor × Referência. O null tem aula própria: null e Tipos Anuláveis.
5. O valor padrão: default
Todo tipo tem um valor padrão, o "zero" daquele tipo. A palavra default mostra qual é:
Console.WriteLine(default(int)); Console.WriteLine(default(double)); Console.WriteLine(default(bool)); Console.WriteLine(default(char) == '\0'); Console.WriteLine(default(string) == null);
$ dotnet run padrao.cs 0 0 False True True
- default(int) … default(double)
- Números valem
0. - default(bool)
false(mostrado comoFalse).- default(char) == '\0'
- O
charpadrão é o caractere de código zero,'\0', que não aparece na tela. Por isso o programa compara em vez de mostrar. - default(string) == null
- Tipos de referência valem
null.
Esses valores padrão aparecem nos campos de classes e nos arrays (new int[3] nasce com três zeros, aula Arrays). Mas uma variável local, criada dentro do programa, não ganha valor padrão: o C# obriga você a dar um valor antes de usar. Veja em "Quando dá errado", abaixo.
6. O tipo decide o que dá para fazer
Multiplicar um int por um decimal funciona, e o resultado é decimal. Juntar um texto com um número, com +, dá um texto:
int quantidade = 3; decimal preco = 2.50m; decimal total = quantidade * preco; Console.WriteLine(total); string texto = "Total: " + total; Console.WriteLine(texto);
$ dotnet run misturar.cs 7,50 Total: 7,50
O int 3 virou decimal sozinho para a conta, porque um inteiro sempre cabe num decimal sem perder nada. Essas conversões automáticas (e as que você precisa pedir) estão em Conversão de Tipos. Repare também que o decimal guarda as casas que você escreveu: 2.50m vezes 3 dá 7,50, com o zero no fim.
Quando dá errado
error CS0029: Não é possível converter implicitamente tipo "string" em "int"
int idade = "29"; Console.WriteLine(idade);
$ dotnet run errotipo.cs /home/ana/cs/errotipo.cs(1,13): error CS0029: Não é possível converter implicitamente tipo "string" em "int" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: o valor é de um tipo ("29", entre aspas, é um texto) e a caixa é de outro (int). (1,13) é a linha 1, coluna 13: o lugar do "29". Em inglês, para pesquisar: Cannot implicitly convert type 'string' to 'int'. Como ler essas mensagens: Lendo Erros do Compilador.
Como consertar: tire as aspas (int idade = 29;). Se o número realmente vem num texto (do teclado, de um arquivo), converta com int.Parse ou int.TryParse: aula Texto → Número.
error CS0266: Não é possível converter implicitamente tipo "double" em "int". Existe uma conversão explícita…
int idade = 29; idade = 29.5; Console.WriteLine(idade);
$ dotnet run errotipo2.cs /home/ana/cs/errotipo2.cs(2,9): error CS0266: Não é possível converter implicitamente tipo "double" em "int". Existe uma conversão explícita (há uma conversão ausente?) Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: a variável nasceu int e continua int para sempre. Guardar 29.5 nela perderia o ,5, e o C# não perde dados sem você pedir. "Existe uma conversão explícita" quer dizer: dá para forçar, se você quiser (o cast, (int)29.5, aula Conversão de Tipos).
Como consertar: se a informação pode ter vírgula, a variável tem de ser double (ou decimal) desde o começo: double idade = 29;.
error CS0165: Uso de variável local não atribuída "pontos"
int pontos; Console.WriteLine(pontos);
$ dotnet run semvalor.cs /home/ana/cs/semvalor.cs(2,19): error CS0165: Uso de variável local não atribuída "pontos" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: a caixa pontos foi criada, mas nunca recebeu valor, e o programa tentou ler. Em outras linguagens isso mostraria "lixo" da memória; o C# simplesmente não deixa. Em inglês: Use of unassigned local variable 'pontos'.
Como consertar: dê um valor antes de usar: int pontos = 0;.
O que significa: não é erro. O código usa ponto (1.65); a saída usa o jeito do país do computador, e o Ubuntu da Ana está em pt-BR (1,65). Num computador em inglês, o mesmo programa mostraria 1.65.
Como consertar: se você precisa de uma saída igual em qualquer computador (um arquivo para outro programa ler, por exemplo), use CultureInfo.InvariantCulture: aula Cultura.
Referência rápida
| Tipo | Para | Exemplo | Mostra | Padrão |
|---|---|---|---|---|
int | contagens | int idade = 29; | 29 | 0 |
double | medidas | double altura = 1.65; | 1,65 | 0 |
decimal | dinheiro | decimal preco = 19.90m; | 19,90 | 0 |
char | um caractere | char letra = 'A'; | A | '\0' |
bool | sim/não | bool ativo = true; | True | false |
string | texto | string nome = "Ana"; | Ana | null |
sizeof(tipo): bytes do tipo · valor.GetType(): o tipo .NET (System.Int32) · typeof(tipo): o tipo em si · default(tipo): o valor padrão. | ||||
Exercícios
1. O tipo do preço
Complete com o tipo certo para guardar o preço de um caderno:
2. O nome .NET
Qual é o nome .NET (com System.) do tipo int?
3. Quantos bytes?
O que Console.WriteLine(sizeof(long)); mostra?
4. Qual tipo serve para guardar um CEP como 01310-100?
5. O que Console.WriteLine(false); mostra?
6. int x; Console.WriteLine(x); dentro do programa. O que acontece?
Missão final: a ficha do caderno
Missão: a lojinha da Ana cadastrou 12 cadernos de R$ 4,50. Troque cada TIPO pelo tipo certo (um texto, uma contagem, um preço e um sim/não). Enquanto houver um TIPO, o compilador reclama que não conhece esse tipo (CS0246). Quando todos estiverem certos, o programa vai compilar e mostrar Total: 54,00 na última linha.
TIPO produto = "Caderno";
TIPO quantidade = 12;
TIPO preco = 4.50m;
TIPO emEstoque = true;
Console.WriteLine("Produto: " + produto);
Console.WriteLine("Em estoque: " + emEstoque);
Console.WriteLine("Total: " + quantidade * preco);
string produto = "Caderno";
int quantidade = 12;
decimal preco = 4.50m;
bool emEstoque = true;
Console.WriteLine("Produto: " + produto);
Console.WriteLine("Em estoque: " + emEstoque);
Console.WriteLine("Total: " + quantidade * preco);
Na solução, a saída é:
$ dotnet run caderno.cs Produto: Caderno Em estoque: True Total: 54,00
Resumo
- Toda variável tem um tipo, decidido no código e conferido na compilação. Ele nunca muda.
- Os seis do dia a dia:
int(contagens),double(medidas),decimal(dinheiro, comm),char('A'),bool(true/false) estring("Ana"). - No código, a vírgula é ponto (
1.65); na saída em pt-BR, vírgula (1,65).trueaparece comoTrue. - Os tamanhos são fixos em qualquer computador:
int4 bytes,long8,double8,decimal16,char2 (sizeof). - As palavras-chave são apelidos de tipos .NET:
int=System.Int32,string=System.String(GetType()). default: números 0,boolfalse, referênciasnull. Variáveis locais precisam de valor antes do uso (CS0165).- Tipo errado na caixa:
CS0029(não existe conversão) ouCS0266(existe, mas você precisa pedir).