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.

Você vai aprender
  • O que o var faz: 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 aceita null (CS0815), uma variável por vez (CS0819), só dentro de métodos (CS0825).
  • O new() com tipo alvo, o "contrário" do var.
  • Quando usar var e 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 "new com 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çãoRecomendaçãoExemplo
O tipo aparece do lado direitovarvar compras = new List<string>();
O valor é óbviotanto faz; var é comumvar nome = "Ana";, var idade = 29;
Dinheiroescreva decimal, ou var com m sem esquecerdecimal preco = 19.90m;
O tipo não está claro pelo valorescreva o tipolong grande = 3_000_000_000;, byte b = 10;
O valor vem de um método de nome vagoescreva o tipoint total = Calcular(); (o que Calcular devolve?)
Sem valor inicial, ou nullobrigatório escrever o tipostring? apelido = null;
Campo de classeobrigató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.

O preço saiu 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

Valorvar vira
"Ana"string
'A'char
29int (ou uint, long, ulong, se não couber)
29Llong
1.65double
1.65ffloat
19.90mdecimal
truebool
new List<string>()List<string>
7 / 2int (vale 3)
nullnão compila (CS0815)

Exercícios

1. A palavra da inferência

Complete para o compilador descobrir o tipo sozinho:

cidade = "Recife";

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:

var salario = 3200.00;

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

  • var pede 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 (use 19.90m para dinheiro), 3_000_000_000 é uint, 7 / 2 é int.
  • Regras: precisa de valor (CS0818), não aceita null (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 var quando o tipo for óbvio; escreva o tipo quando não for.