C# Interpolação

Até agora, para montar uma frase com variáveis, você colou pedaços com +: nome + " tem " + idade + " anos". Funciona, mas é fácil esquecer um espaço, e as aspas e os + se acumulam. O C# tem um jeito muito mais limpo: a interpolação. Você escreve a frase inteira e marca, entre chaves, onde entram os valores: $"{nome} tem {idade} anos". É a forma que você vai encontrar em quase todo código C# moderno. Nesta aula você vai ver como ela funciona, o que pode ir dentro das chaves e os erros mais comuns.

Você vai aprender
  • Montar textos com $"…{variavel}…" e por que isso é melhor que o +.
  • Colocar contas, métodos e comparações dentro das chaves.
  • Por que o operador ? : precisa de parênteses dentro das chaves.
  • Uma prévia da formatação ({preco:C}, {nome,-10}) e como escrever chaves de verdade ({{ }}).
  • As outras formas (+, string.Format) e os erros reais do compilador.

Todos os programas desta aula foram rodados com o .NET 10 na máquina fictícia da Ana (usuária ana, computador notebook, sistema em português do Brasil), na pasta ~/cs, com dotnet run arquivo.cs.


A ideia: um formulário com lacunas

Pense numa ficha de inscrição impressa: "Eu, ________, de ____ anos, moro em ________." O texto está pronto; só faltam as lacunas. Você preenche cada uma com a informação certa.

A interpolação é essa ficha. O $ antes das aspas avisa: "este texto tem lacunas". Cada lacuna é um par de chaves { }, e dentro dele vai o que deve ser escrito ali. A palavra "interpolar" quer dizer exatamente isso: "colocar no meio".


1. A primeira interpolação

string nome = "Ana";
int idade = 29;
Console.WriteLine($"Olá, {nome}!");
Console.WriteLine($"{nome} tem {idade} anos.");
Console.WriteLine(nome + " tem " + idade + " anos.");
$ dotnet run ola.cs
Olá, Ana!
Ana tem 29 anos.
Ana tem 29 anos.     « o mesmo resultado, com +
$"…"
O cifrão colado nas aspas transforma o texto numa string interpolada. Sem o $, as chaves seriam só caracteres comuns.
{nome}
Uma lacuna. Na hora de rodar, o C# troca {nome} pelo valor da variável: Ana.
{idade}
Números também entram: o C# converte para texto sozinho. Não precisa de +, nem de ToString().
linha 5
A mesma frase com +: repare quantas aspas e espaços você precisa controlar. Na interpolação, os espaços ficam visíveis dentro do texto, onde você espera.

O resultado é uma string normal, que pode ser guardada numa variável: string saudacao = $"Bom dia, {nome}!";.

Missão: a apresentação da Ana saiu toda grudada: Anatem29anos e mora emRecife.. Reescreva a linha do WriteLine com interpolação ($"…") para aparecer Ana tem 29 anos e mora em Recife.

Ana tem 29 anos e mora em Recife.
string nome = "Ana";
int idade = 29;
string cidade = "Recife";
Console.WriteLine(nome + "tem" + idade + "anos e mora em" + cidade + ".");
string nome = "Ana";
int idade = 29;
string cidade = "Recife";
Console.WriteLine($"{nome} tem {idade} anos e mora em {cidade}.");

2. Dentro das chaves vai qualquer expressão

Uma lacuna não precisa ser só uma variável. Pode ser qualquer expressão, qualquer coisa que produza um valor: uma conta, um método, uma comparação.

string nome = "Ana";
int idade = 29;
decimal preco = 12.5m;
int quantidade = 3;
Console.WriteLine($"Ano que vem, {nome} terá {idade + 1} anos.");
Console.WriteLine($"Total: {preco * quantidade}");
Console.WriteLine($"Em maiúsculas: {nome.ToUpper()}");
Console.WriteLine($"O nome tem {nome.Length} letras.");
Console.WriteLine($"Maior de idade? {idade >= 18}");
Console.WriteLine($"Média: {(7 + 8) / 2.0}");
$ dotnet run expr.cs
Ano que vem, Ana terá 30 anos.     « a conta foi feita antes de entrar no texto
Total: 37,5                        « vírgula: a cultura da máquina é pt-BR
Em maiúsculas: ANA
O nome tem 3 letras.
Maior de idade? True
Média: 7,5

Repare na linha do idade >= 18: na aula Operadores de Comparação, com +, essa comparação precisava de parênteses ("…" + (idade >= 18)), senão dava erro. Dentro das chaves, ela é calculada sozinha, e o problema some. O mesmo vale para a conta: {idade + 1} nunca vira "291", como aconteceria com "…" + idade + 1 (aula Precedência).

Os números aparecem com vírgula decimal (37,5) porque a interpolação usa a cultura do computador, que na máquina da Ana é pt-BR. Num computador em inglês, sairia 37.5 (aula Cultura).

Mantenha as chaves simples

Dá para pôr muita coisa dentro das chaves, mas uma conta grande no meio da frase fica difícil de ler. Se a expressão passou de uma conta simples, calcule antes numa variável com nome: decimal total = preco * quantidade; e depois $"Total: {total}".

O ? : precisa de parênteses

O operador ternário (condição ? sim : não, aula Operador Ternário) escolhe entre dois valores. Dentro das chaves, ele vai entre parênteses:

int idade = 15;
Console.WriteLine($"Situação: {(idade >= 18 ? "adulto" : "menor")}");
$ dotnet run ternario.cs
Situação: menor

O motivo: dentro das chaves, o : tem outro trabalho, que é começar a formatação (próxima seção). Sem os parênteses, o C# acha que "menor" é um formato e se perde. O erro está em Quando dá errado. Repare também que dá para usar aspas ("adulto") dentro das chaves.


3. Formatar e alinhar dentro das chaves

Depois do valor, dentro das mesmas chaves, você pode dizer como ele deve aparecer: com : vem o formato, e com , vem a largura.

decimal preco = 1234.5m;
double media = 7.456;
Console.WriteLine($"Preço: {preco:C}");
Console.WriteLine($"Média: {media:F1}");
Console.WriteLine($"[{"Ana",-8}] [{"Bia",8}]");
Console.WriteLine($"{3.5}");
$ dotnet run fmt.cs
Preço: R$ 1.234,50       « C = moeda (currency), pelas regras do Brasil
Média: 7,5               « F1 = uma casa depois da vírgula (arredondada)
[Ana     ] [     Bia]    « ,-8 = 8 de largura, encostado à esquerda; ,8 = à direita
3,5
{preco:C}
O C (currency, "moeda") mostra o valor como dinheiro, no padrão do país do computador: R$, ponto nos milhares, vírgula e duas casas.
{media:F1}
"Ponto fixo com 1 casa decimal": 7,456 vira 7,5 (arredondado).
{"Ana",-8}
Reserva 8 posições para o valor. Negativo: o texto encosta à esquerda e os espaços vão depois. Positivo: encosta à direita.

Esses formatos são todo um assunto, com uma aula só para eles: Formatar Números (N2, C, P). Aqui basta saber que eles moram dentro das chaves, depois do : e da ,.


4. Como escrever uma chave de verdade

E se você quiser que apareça uma chave no texto, como em {nome}? Numa string interpolada, dobre a chave: {{ vira { e }} vira }.

string nome = "Ana";
Console.WriteLine($"{{nome}} vale {nome}");
Console.WriteLine($"Conjunto: {{ {1}, {2}, {3} }}");
$ dotnet run chaves.cs
{nome} vale Ana          « {{nome}} virou o texto {nome}; {nome} virou Ana
Conjunto: { 1, 2, 3 }

Numa string comum (sem $), as chaves não têm nada de especial e não precisam ser dobradas. Para textos com muitas chaves, como um JSON, existe a string bruta interpolada $"""…""" C# 11, explicada em Escapes e Strings Literais.


Formas diferentes de montar o mesmo texto

string nome = "Ana";
int idade = 29;
Console.WriteLine(nome + " tem " + idade + " anos.");
Console.WriteLine(string.Format("{0} tem {1} anos.", nome, idade));
Console.WriteLine($"{nome} tem {idade} anos.");
Console.WriteLine("{0} tem {1} anos.", nome, idade);
$ dotnet run formas.cs
Ana tem 29 anos.
Ana tem 29 anos.
Ana tem 29 anos.
Ana tem 29 anos.
FormaComo funcionaQual usar
nome + " tem " + idadeConcatenação: cola os pedaços (aula Strings).Para juntar dois pedaços: nome + "!".
string.Format("{0} tem {1}", nome, idade)Lacunas numeradas: {0} é o primeiro valor depois do texto, {1} o segundo.Código antigo (antes do C# 6) e textos guardados fora do código, como traduções.
$"{nome} tem {idade}" C# 6Interpolação: o valor fica no lugar onde aparece.O padrão para quase tudo. Você lê a frase como ela vai sair.
Console.WriteLine("{0} tem {1}", nome, idade)O próprio WriteLine faz o string.Format.Aparece em tutoriais antigos. Prefira a interpolação.

O string.Format tem uma armadilha: se o texto pede {1} e você passa um valor só, o erro só aparece quando o programa roda (veja abaixo). Na interpolação, o valor está escrito dentro da lacuna, e esse erro não existe.


Quando dá errado

Apareceu {nome} na tela, com as chaves
string nome = "Ana";
Console.WriteLine("Olá, {nome}!");
$ dotnet run ei1.cs
/home/ana/cs/ei1.cs(1,8): warning CS0219: A variável "nome" é atribuída, mas seu valor nunca é usado
Olá, {nome}!

O que significa: faltou o $. Sem ele, {nome} é só texto. O único sinal do compilador é o aviso CS0219: "a variável nome nunca é usada", porque para ele, de fato, não foi. Se a variável fosse usada em outra linha, nem esse aviso apareceria.

Como consertar: $"Olá, {nome}!", com o $ colado nas aspas.

error CS8361: Uma expressão condicional não pode ser usada diretamente em uma interpolação de cadeia de caracteres porque ‘:’ encerra a interpolação.
int idade = 15;
Console.WriteLine($"Situação: {idade >= 18 ? "adulto" : "menor"}");
$ dotnet run ei2.cs
/home/ana/cs/ei2.cs(2,30): error CS8076: Delimitador de fechamento ausente '}' para expressão interpolada iniciada com '{'.
/home/ana/cs/ei2.cs(2,32): error CS8361: Uma expressão condicional não pode ser usada diretamente em uma interpolação de cadeia de caracteres porque ‘:’ encerra a interpolação. Use parênteses na expressão condicional.
/home/ana/cs/ei2.cs(2,58): error CS1003: Erro de sintaxe, "," esperado
/home/ana/cs/ei2.cs(2,63): error CS1003: Erro de sintaxe, "," esperado

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O que significa: quatro erros para um problema só. O que explica tudo é o CS8361: o : do ternário foi lido como o começo de um formato. Os outros (CS8076, CS1003) são consequência. Quando aparecerem vários erros na mesma linha, procure o que faz sentido e conserte esse primeiro.

Como consertar: parênteses em volta do ternário, como a própria mensagem pede: {(idade >= 18 ? "adulto" : "menor")}.

error CS8076: Delimitador de fechamento ausente '}' para expressão interpolada iniciada com '{'.
string nome = "Ana";
Console.WriteLine($"Olá, {nome!");
$ dotnet run ei3.cs
/home/ana/cs/ei3.cs(2,25): error CS8076: Delimitador de fechamento ausente '}' para expressão interpolada iniciada com '{'.
/home/ana/cs/ei3.cs(2,27): error CS1073: Token inesperado '");'
/home/ana/cs/ei3.cs(2,32): error CS1010: Newline em constante
/home/ana/cs/ei3.cs(3,1): error CS1026: ) esperado
/home/ana/cs/ei3.cs(3,1): error CS1002: ; esperado

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O que significa: uma chave abriu (coluna 25) e não fechou. O C# continuou lendo o resto da linha como se fosse código, e os outros quatro erros são o efeito dominó.

Como consertar: feche a chave: $"Olá, {nome}!".

error CS8086: Um caractere '}' deve ser de escape (ao duplicar) em uma cadeia de caracteres interpolada.
string nome = "Ana";
Console.WriteLine($"Olá, {nome}}!");
$ dotnet run ei5.cs
/home/ana/cs/ei5.cs(2,32): error CS8086: Um caractere '}' deve ser de escape (ao duplicar) em uma cadeia de caracteres interpolada.

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O que significa: sobrou uma } sozinha. Numa string interpolada, para escrever uma chave de verdade, é preciso dobrá-la.

Como consertar: apague a chave que sobrou, ou dobre-a (}}) se ela devia aparecer no texto.

error CS0103: O nome "Nome" não existe no contexto atual
string nome = "Ana";
Console.WriteLine($"Olá, {Nome}!");
$ dotnet run ei4.cs
/home/ana/cs/ei4.cs(2,27): error CS0103: O nome "Nome" não existe no contexto atual
/home/ana/cs/ei4.cs(1,8): warning CS0219: A variável "nome" é atribuída, mas seu valor nunca é usado

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O que significa: o que está dentro das chaves é código, e o compilador confere. Nome (maiúsculo) não é nome. É uma vantagem da interpolação: um nome errado é pego antes de rodar.

Como consertar: escreva o nome exatamente como foi declarado: {nome}.

System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
Console.WriteLine(string.Format("{0} e {1}", "Ana"));
$ dotnet run ei6.cs
Unhandled exception. System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
   at System.Text.ValueStringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ReadOnlySpan`1 args)
   at System.String.FormatHelper(IFormatProvider provider, String format, ReadOnlySpan`1 args)
   at System.String.Format(String format, Object arg0)
   at Program.<Main>$(String[] args) in /home/ana/cs/ei6.cs:line 1

O que significa: o texto do string.Format pede a lacuna {1} (o segundo valor), mas só um valor foi passado. "O índice (contado do zero) precisa ser menor que o tamanho da lista de argumentos." O compilador não conferiu; o erro só apareceu ao rodar.

Como consertar: passe um valor para cada lacuna, ou, melhor, troque por interpolação: $"{nome1} e {nome2}".


Referência

EscritaO que fazExemplo → resultado
$"…{x}…"põe o valor de x no texto$"Oi, {nome}" → Oi, Ana
{conta}calcula e põe o resultado$"{2 + 3}" → 5
{x.Metodo()}chama o método e põe o resultado$"{nome.ToUpper()}" → ANA
{(c ? a : b)}ternário, sempre entre parênteses$"{(n > 0 ? "sim" : "não")}"
{x:formato}formata o valor$"{1234.5m:C}" → R$ 1.234,50
{x,largura}alinha à direita em largura posições$"[{"oi",4}]" → [ oi]
{x,-largura}alinha à esquerda$"[{"oi",-4}]" → [oi ]
{x,largura:formato}as duas coisas juntas$"{preco,12:C}"
{{ e }}uma chave de verdade$"{{x}}" → {x}
$@"…", $"""…"""interpolação com string literal ou brutaaula Escapes

Exercícios

1. O símbolo que falta

Complete para a frase mostrar o nome:

Console.WriteLine("Olá, {nome}!");

2. A lacuna

Complete para mostrar a idade da Ana daqui a 5 anos:

$"Em 2031, terei anos"

3. Chaves de verdade

O que $"{{{2 * 3}}}" mostra?

Saída:

4. O que Console.WriteLine("Total: {total}"); mostra, com total valendo 50?

5. Por que $"{x > 0 ? "sim" : "não"}" não compila?

6. Com int idade = 29;, o que $"Ano que vem: {idade + 1}" mostra?

Missão final: o ingresso

Missão: a Ana comprou 3 ingressos de R$ 12,50. Escreva uma linha com interpolação que mostre Ana comprou 3 ingressos: total 37,50. O total tem de ser calculado dentro das chaves (preco * quantidade), e o nome e a quantidade vêm das variáveis.

Ana comprou 3 ingressos: total 37,50
string nome = "Ana";
int quantidade = 3;
decimal preco = 12.50m;
// escreva aqui o Console.WriteLine com $"…"
string nome = "Ana";
int quantidade = 3;
decimal preco = 12.50m;
Console.WriteLine($"{nome} comprou {quantidade} ingressos: total {preco * quantidade}");

O total saiu 37,50, com duas casas, porque o decimal lembra as casas do 12.50m. Experimente {preco * quantidade:C} e veja o R$ aparecer.


Resumo

  • Interpolação: $"…{valor}…". O $ colado nas aspas; cada { } é uma lacuna.
  • Dentro das chaves vai qualquer expressão: {idade + 1}, {nome.ToUpper()}, {idade >= 18}.
  • O ternário vai entre parênteses: {(cond ? a : b)}; senão, CS8361.
  • {x:C} formata, {x,10} alinha (aula Formatar Números). Os números seguem a cultura (37,5).
  • Chave de verdade: {{ e }}.
  • Sem o $, as chaves aparecem na tela. Chave sem fechar: CS8076; chave sobrando: CS8086.
  • Prefira a interpolação ao + com vários pedaços e ao string.Format.