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.
- 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 deToString(). - 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).
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.
| Forma | Como funciona | Qual usar |
|---|---|---|
nome + " tem " + idade | Concatenaçã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# 6 | Interpolaçã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
{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
| Escrita | O que faz | Exemplo → 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 bruta | aula Escapes |
Exercícios
1. O símbolo que falta
Complete para a frase mostrar o nome:
2. A lacuna
Complete para mostrar a idade da Ana daqui a 5 anos:
3. Chaves de verdade
O que $"{{{2 * 3}}}" mostra?
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 aostring.Format.