C# Inferência com var
Até aqui, toda variável começou com o nome do tipo: int idade = 29;, string nome = "Ana";. Mas repare: o 29 já diz que é um inteiro, e o "Ana" já diz que é texto. O C# deixa você trocar o tipo pela palavra var e descobre o tipo sozinho, olhando o valor. Isso se chama inferência de tipo. Nesta aula você vai ver como o var funciona, o que ele não faz (ele não deixa a variável mudar de tipo) e a armadilha do preço com var.
- O que o
varfaz: o compilador escolhe o tipo pelo valor do lado direito. - Que a variável continua com um tipo fixo, para sempre (
CS0029). - Como o C# escolhe o tipo de cada valor:
19.90édouble,19.90médecimal. - As regras do
var: precisa de valor (CS0818), não aceitanull(CS0815), uma variável por vez (CS0819), só dentro de métodos (CS0825). - O
new()com tipo alvo, o "contrário" dovar. - Quando usar
vare quando escrever o tipo.
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), na pasta ~/cs, com dotnet run arquivo.cs.
A ideia: a etiqueta que se escreve sozinha
Imagine uma etiquetadora mágica na cozinha da Ana. Ela coloca açúcar num pote vazio, e a etiqueta "AÇÚCAR" aparece sozinha. Ela não precisou escrever, mas a etiqueta está lá, e o pote continua sendo de açúcar: ninguém vai pôr feijão nele depois.
O var é essa etiquetadora. Você escreve var, põe um valor, e o compilador "escreve a etiqueta" (o tipo) por você, na hora de compilar. Depois disso, a variável é exatamente igual a uma declarada com o tipo escrito.
1. var no lugar do tipo
var nome = "Ana"; var idade = 29; var altura = 1.65; var saldo = 1250.75m; var inicial = 'A'; var ativa = true; Console.WriteLine(nome.GetType()); Console.WriteLine(idade.GetType()); Console.WriteLine(altura.GetType()); Console.WriteLine(saldo.GetType()); Console.WriteLine(inicial.GetType()); Console.WriteLine(ativa.GetType());
$ dotnet run var1.cs System.String System.Int32 System.Double System.Decimal System.Char System.Boolean
- var
- Abreviação de variable, "variável". Quer dizer: "compilador, descubra o tipo pelo valor". Existe desde o C# 3 (2007) e aparece em quase todo código moderno.
- var nome = "Ana";
- Aspas duplas:
string(System.String). - var idade = 29;
- Número sem ponto:
int. - var altura = 1.65;
- Número com ponto e sem sufixo:
double. - var saldo = 1250.75m;
- Com o sufixo
m:decimal. - var inicial = 'A'; · var ativa = true;
- Aspas simples:
char.true:bool.
Os tipos são exatamente os da aula Tipos de Dados, em que cada linha tinha o tipo escrito. O programa gerado é o mesmo: var só poupa você de digitar o tipo. Num editor como o VS Code, passe o mouse em cima do nome da variável para ver o tipo que o compilador escolheu (aula Editores e IDEs).
2. O tipo continua fixo
Em JavaScript e Python, uma variável pode guardar um número agora e um texto depois. Com var, o C# não vira isso. O tipo é decidido uma vez, pelo primeiro valor, e nunca mais muda:
var pontos = 10; pontos = "dez"; Console.WriteLine(pontos);
$ dotnet run varerro3.cs /home/ana/cs/varerro3.cs(2,10): 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.
pontos nasceu int (por causa do 10) e é int para sempre. É o mesmo erro que você teria com int pontos = 10;. O var não deixa o C# "solto"; ele só escreve o tipo por você.
3. O tipo vem do valor: cuidado com o preço
Como o var copia o tipo do valor, você precisa saber qual é o tipo de cada valor. A armadilha mais comum é com dinheiro:
var preco = 19.90; Console.WriteLine(preco.GetType()); Console.WriteLine(preco * 3); var precoCerto = 19.90m; Console.WriteLine(precoCerto * 3);
$ dotnet run varpreco.cs System.Double 59,699999999999996 « três camisetas de R$ 19,90, em double 59,70 « em decimal
Com o tipo escrito, decimal preco = 19.90; nem compilaria (CS0664, aula float, double e decimal): o compilador avisaria que faltou o m. Com var, não há o que avisar: 19.90 é um double válido, e a variável vira double sem reclamar. O erro só aparece no resultado. Moral: com var, dinheiro precisa do m.
Missão: o caixa cobra três camisetas e mostra Total: 59,699999999999996. Sem tirar o var, faça preco ser decimal para mostrar Total: 59,70.
var preco = 19.90;
var quantidade = 3;
Console.WriteLine("Total: " + preco * quantidade);
var preco = 19.90m;
var quantidade = 3;
Console.WriteLine("Total: " + preco * quantidade);
Outras escolhas que você precisa conhecer
var pequeno = 100; var grande = 3_000_000_000; var maior = 8_000_000_000; var b = (byte)10; Console.WriteLine(pequeno.GetType()); Console.WriteLine(grande.GetType()); Console.WriteLine(maior.GetType()); Console.WriteLine(b.GetType());
$ dotnet run vargrande.cs System.Int32 System.UInt32 « 3 bilhões não cabe em int: virou uint! System.Int64 System.Byte
Um número inteiro ganha o primeiro tipo em que cabe: int, uint, long, ulong (aula Inteiros). Por isso 3 bilhões virou uint (sem sinal!) e 8 bilhões virou long. Se você quer um long, diga: var grande = 3_000_000_000L; ou long grande = 3_000_000_000;. E para tipos sem literal próprio, como byte e short, o var precisa de uma conversão, (byte)10; aí é mais claro escrever byte b = 10;.
O mesmo vale para contas: o tipo é o do resultado.
var notaA = 7; var notaB = 8; var media = (notaA + notaB) / 2; Console.WriteLine(media); Console.WriteLine(media.GetType());
$ dotnet run varconta.cs 7 « a média de 7 e 8 devia ser 7,5 System.Int32
int dividido por int dá int, e a parte quebrada some (aula Operadores Aritméticos). O var só copiou o tipo do resultado. Com (notaA + notaB) / 2.0, a conta seria double e a variável também.
4. As regras do var
Precisa de um valor na mesma linha
var total; total = 10; Console.WriteLine(total);
$ dotnet run varerro1.cs /home/ana/cs/varerro1.cs(1,5): error CS0818: Variáveis de tipo implícito devem ser inicializadas Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
"Tipo implícito" é o tipo que o compilador descobre; "inicializar" é dar o primeiro valor. Sem valor, não há de onde tirar o tipo. Em inglês: Implicitly-typed variables must be initialized.
Não aceita null
var apelido = null; Console.WriteLine(apelido);
$ dotnet run varerro2.cs /home/ana/cs/varerro2.cs(1,5): error CS0815: Não é possível atribuir <nulo> a uma variável de tipo implícito Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
null ("nada") não tem tipo, então não serve de pista. Escreva o tipo: string? apelido = null; (o ? é explicado em Referências Anuláveis).
Uma variável por declaração
var a = 1, b = 2; Console.WriteLine(a + b);
$ dotnet run varerro4.cs /home/ana/cs/varerro4.cs(1,1): error CS0819: Variáveis de tipo implícito não podem ter vários declaradores Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
Com o tipo escrito, int a = 1, b = 2; funciona. Com var, uma linha para cada: var a = 1; e var b = 2;.
Só para variáveis locais
O var funciona para variáveis criadas dentro do programa ou de um método (as locais). Nos campos de uma classe, o tipo tem de ser escrito:
class Loja
{
var nome = "Lojinha";
}
$ dotnet run varfield.cs /home/ana/cs/varfield.cs(3,5): error CS0825: A palavra-chave contextual "var" pode somente aparecer dentro de uma declaração de variável local ou no código de script Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O conserto é string nome = "Lojinha";. Classes e campos começam em Classes e Objetos. A mensagem diz "palavra-chave contextual": o var só é especial no lugar de um tipo. Em outros lugares, ele é um nome comum, e int var = 5; até compila (mas não faça isso).
5. O contrário: new() com tipo alvo
O var brilha quando o tipo já aparece do lado direito, como ao criar uma lista com new. E existe o caminho inverso C# 9: escrever o tipo à esquerda e só new() à direita:
var compras = new List<string>();
compras.Add("arroz");
compras.Add("feijão");
List<string> outras = new();
outras.Add("café");
Console.WriteLine(compras.Count);
Console.WriteLine(outras.Count);
$ dotnet run varnew.cs 2 1
- var compras = new List<string>();
- Cria uma lista de textos (aula List<T>). O tipo
List<string>já está escrito do lado direito; repetir à esquerda seria cansativo. - List<string> outras = new();
- O "
newcom tipo alvo": o compilador olha o tipo da variável e sabe o que criar. Dá no mesmo; o tipo aparece uma vez só. - .Add · .Count
- Adiciona um item; conta os itens.
As duas formas são comuns. O new() é a única opção nos lugares em que var não vale, como os campos de uma classe.
Quando usar var
| Situação | Recomendação | Exemplo |
|---|---|---|
| O tipo aparece do lado direito | var | var compras = new List<string>(); |
| O valor é óbvio | tanto faz; var é comum | var nome = "Ana";, var idade = 29; |
| Dinheiro | escreva decimal, ou var com m sem esquecer | decimal preco = 19.90m; |
| O tipo não está claro pelo valor | escreva o tipo | long grande = 3_000_000_000;, byte b = 10; |
| O valor vem de um método de nome vago | escreva o tipo | int total = Calcular(); (o que Calcular devolve?) |
Sem valor inicial, ou null | obrigatório escrever o tipo | string? apelido = null; |
| Campo de classe | obrigatório escrever o tipo (ou new()) | string nome = "Lojinha"; |
A regra prática da Microsoft é: use var quando o tipo for óbvio para quem lê; escreva o tipo quando não for. Neste guia, as primeiras aulas escrevem os tipos (para você aprender cada um), e o var aparece mais a partir das coleções e do LINQ, onde os tipos ficam longos.
Quando dá errado
error CS0818: Variáveis de tipo implícito devem ser inicializadas
O que significa: var x; sem valor. O compilador não tem de onde tirar o tipo.
Como consertar: dê o valor na mesma linha (var total = 0;) ou escreva o tipo (int total;).
error CS0815: Não é possível atribuir <nulo> a uma variável de tipo implícito
O que significa: var x = null;. O null não tem tipo.
Como consertar: escreva o tipo: string? x = null;.
error CS0819: Variáveis de tipo implícito não podem ter vários declaradores
O que significa: var a = 1, b = 2;, duas variáveis num var só.
Como consertar: uma declaração por linha.
error CS0825: A palavra-chave contextual "var" pode somente aparecer dentro de uma declaração de variável local…
O que significa: var num campo de classe, num parâmetro ou no tipo de retorno de um método.
Como consertar: escreva o tipo.
error CS0029 numa variável declarada com var
O que significa: a variável ganhou um tipo no primeiro valor e você tentou guardar outro tipo depois.
Como consertar: use outra variável para o outro valor, ou escolha um primeiro valor do tipo certo.
59,699999999999996; a média saiu sem vírgula; o número grande virou uint
O que significa: nada de errado com o var: ele copiou fielmente o tipo do valor (double, int, uint), que não era o que você queria.
Como consertar: mude o valor (19.90m, / 2.0, 3_000_000_000L) ou escreva o tipo.
Referência rápida
| Valor | var vira |
|---|---|
"Ana" | string |
'A' | char |
29 | int (ou uint, long, ulong, se não couber) |
29L | long |
1.65 | double |
1.65f | float |
19.90m | decimal |
true | bool |
new List<string>() | List<string> |
7 / 2 | int (vale 3) |
null | não compila (CS0815) |
Exercícios
1. A palavra da inferência
Complete para o compilador descobrir o tipo sozinho:
2. Qual tipo?
Em var temperatura = 23.5;, qual é o tipo de temperatura? (Escreva a palavra-chave.)
3. Dinheiro com var
Complete para salario ser decimal:
4. var x = 10; x = 2.5; O que acontece?
5. Qual destas linhas compila?
6. Quando o var descobre o tipo?
Missão final: a ficha com var
Missão: reescreva as três declarações usando var no lugar dos tipos, sem mudar a saída: Bia tem 31 anos e R$ 250,50. Cuidado com o saldo: ele tem de continuar decimal.
string nome = "Bia";
int idade = 31;
decimal saldo = 250.50m;
Console.WriteLine($"{nome} tem {idade} anos e R$ {saldo}");
var nome = "Bia";
var idade = 31;
var saldo = 250.50m;
Console.WriteLine($"{nome} tem {idade} anos e R$ {saldo}");
Tente também escrever var saldo = 250.50; (sem o m): a saída muda para R$ 250,5, porque o double não guarda o zero do fim. É o sinal de que o tipo mudou.
Resumo
varpede ao compilador para descobrir o tipo pelo valor (inferência). Acontece na compilação; o programa é igual ao com o tipo escrito.- O tipo continua fixo:
var pontos = 10; pontos = "dez";dáCS0029. - O tipo é o do valor:
19.90édouble(use19.90mpara dinheiro),3_000_000_000éuint,7 / 2éint. - Regras: precisa de valor (
CS0818), não aceitanull(CS0815), uma variável por vez (CS0819), só variáveis locais (CS0825). List<string> lista = new();é o caminho inverso C# 9: o tipo à esquerda, sónew()à direita.- Use
varquando o tipo for óbvio; escreva o tipo quando não for.