C# Sintaxe
Toda língua tem regras de escrita. Em português, a frase começa com maiúscula e termina com ponto; em C#, a instrução termina com ;, os textos ficam entre aspas e os blocos ficam entre chaves. Esse conjunto de regras se chama sintaxe. A diferença é que um leitor humano entende uma frase com um errinho, e o compilador não: uma vírgula fora do lugar e o programa nem chega a rodar. Nesta aula você aprende as regras de escrita que valem para todo programa C#, e as mensagens que aparecem quando uma delas é quebrada.
- O que é uma instrução, por que ela termina com
;e em que ordem as instruções rodam. - Onde os espaços e as quebras de linha importam (quase nunca) e onde não podem aparecer.
- Por que
Consoleeconsolesão coisas diferentes. - Para que servem os sinais
( )," ",.e{ }. - O que é um bloco, o recuo e o estilo de chaves do C#, e como o
dotnet formatarruma o código. - A diferença entre instrução e expressão.
- Os erros de sintaxe mais comuns, com a mensagem real e o conserto.
Os programas desta aula foram rodados na máquina fictícia da Ana com o .NET 10 SDK (C# 14), na pasta ~/cs/sintaxe, com dotnet run arquivo.cs. As mensagens saem em português, como num Ubuntu em pt-BR, e o código CSxxxx de cada uma é o mesmo em qualquer língua.
A ideia: a receita de bolo
Uma receita é uma lista de passos, um depois do outro: "bata os ovos. Junte o açúcar. Leve ao forno." Cada passo termina com um ponto, e quem cozinha faz um de cada vez, na ordem. Às vezes um grupo de passos vai junto: "para a cobertura: derreta o chocolate e misture o creme".
Um programa C# é igual:
| Na receita | No C# | Exemplo |
|---|---|---|
| Um passo | Uma instrução (statement) | Console.WriteLine("Olá!"); |
| O ponto final do passo | O ponto e vírgula | ; |
| Fazer na ordem | De cima para baixo | a linha 1 roda antes da linha 2 |
| Um grupo de passos ("para a cobertura:") | Um bloco, entre chaves | { … } |
1. Instruções e o ponto e vírgula
Uma instrução é uma ordem completa para o computador. Toda instrução simples termina com ;. O programa roda as instruções na ordem em que estão escritas, de cima para baixo:
Console.WriteLine("1. Acordar");
Console.WriteLine("2. Tomar café");
Console.WriteLine("3. Ir à feira");
$ dotnet run ordem.cs 1. Acordar 2. Tomar café 3. Ir à feira
- Console
- O console, ou seja, o terminal. Em C#, é uma classe: um conjunto de ferramentas com nome. (O
Consoleé do .NET; aulas Saída e Classes e Objetos.) - .
- O ponto quer dizer "de dentro de":
Console.WriteLineé "oWriteLineque mora dentro doConsole". - WriteLine
- "Escrever linha": a ferramenta (o método) que escreve um texto e pula para a linha de baixo.
- ( … )
- Os parênteses mandam o método trabalhar (isso se chama chamar o método) e levam o que ele precisa para trabalhar: aqui, o texto.
- "1. Acordar"
- Um texto, entre aspas duplas retas. As aspas não aparecem na saída: elas só marcam onde o texto começa e termina.
- ;
- O fim da instrução, como o ponto final de uma frase.
Para o compilador, o que separa uma instrução da outra é o ;, e não a quebra de linha. Por isso duas instruções podem dividir a mesma linha:
Console.WriteLine("Bom dia!"); Console.WriteLine("Boa tarde!");
$ dotnet run linha.cs Bom dia! Boa tarde!
Funciona, mas é difícil de ler. A regra de ouro do C# é uma instrução por linha.
E se faltar o ;?
Console.WriteLine("Lista de compras")
Console.WriteLine("Arroz");
$ dotnet run pv.cs /home/ana/cs/sintaxe/pv.cs(1,38): error CS1002: ; esperado Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
A mensagem diz o arquivo, a posição (linha 1, coluna 38, logo depois do )), o código do erro (CS1002) e o que faltou: "; esperado". O programa não roda, nem a parte que estava certa. Como ler cada pedaço dessa mensagem é o assunto de Lendo Erros do Compilador. Em inglês, para pesquisar: ; expected.
Missão: rode e leia o erro. Faltam dois ;. Conserte para o programa mostrar as três linhas.
Console.WriteLine("Feira da Ana")
Console.WriteLine("Arroz");
Console.WriteLine("Feijão")
Console.WriteLine("Feira da Ana");
Console.WriteLine("Arroz");
Console.WriteLine("Feijão");
2. Espaços e quebras de linha
O compilador ignora espaços, tabulações e quebras de linha entre as "palavras" do código. Este programa, todo espalhado, é igual a Console.WriteLine("Olá, Ana!");:
Console
.WriteLine(
"Olá, Ana!"
)
;
$ dotnet run espalhado.cs Olá, Ana!
Isso é útil quando uma instrução fica comprida demais e você quer quebrá-la em várias linhas. Mas existem dois lugares onde não se pode separar:
- Dentro de um nome:
Consoleé uma palavra só;Con solesão duas, e nenhuma delas existe. - Dentro de um texto entre aspas: ali, cada espaço conta (ele aparece na saída), e a quebra de linha é proibida.
Console.WriteLine("Lista de
compras");
$ dotnet run quebra.cs /home/ana/cs/sintaxe/quebra.cs(1,19): error CS1010: Newline em constante /home/ana/cs/sintaxe/quebra.cs(1,28): error CS1003: Erro de sintaxe, "," esperado /home/ana/cs/sintaxe/quebra.cs(2,8): error CS1003: Erro de sintaxe, "," esperado /home/ana/cs/sintaxe/quebra.cs(2,8): error CS1010: Newline em constante /home/ana/cs/sintaxe/quebra.cs(2,11): error CS1026: ) esperado /home/ana/cs/sintaxe/quebra.cs(2,11): error CS1002: ; esperado Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
Seis erros para um engano só. O primeiro é o verdadeiro: CS1010: Newline em constante ("quebra de linha numa constante"; em inglês, Newline in constant). Constante, aqui, é o texto escrito direto no código, e newline é a quebra de linha. A tradução deixou a palavra em inglês no meio da frase. Os outros cinco são consequência: sem as aspas fechadas na linha 1, o compilador se perdeu e tentou entender o resto do jeito que deu. Leia sempre o primeiro erro primeiro.
Para mostrar duas linhas, use dois WriteLine. (Existe também o \n dentro do texto e os textos de várias linhas com """, na aula Escapes e Strings Literais.)
3. Maiúsculas e minúsculas
O C# diferencia maiúsculas de minúsculas (em inglês, ele é case-sensitive). Console, console e CONSOLE são três nomes diferentes, e só o primeiro existe:
console.WriteLine("Olá!");
$ dotnet run minuscula.cs /home/ana/cs/sintaxe/minuscula.cs(1,1): error CS0103: O nome "console" não existe no contexto atual Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
"O nome console não existe no contexto atual": o compilador procurou alguma coisa chamada console, com c minúsculo, e não achou. Esse é o CS0103 (The name 'console' does not exist in the current context), um dos erros que você mais vai ver, também quando digitar errado o nome de uma variável. E com o método em minúsculas:
Console.writeline("Olá!");
$ dotnet run metodo.cs /home/ana/cs/sintaxe/metodo.cs(1,9): error CS0117: "Console" não contém uma definição para "writeline" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
Agora o Console foi encontrado, mas dentro dele não há nada chamado writeline: o certo é WriteLine, com W e L maiúsculos. A coluna 9 aponta o começo do writeline, logo depois do ponto. Em inglês: 'Console' does not contain a definition for 'writeline'.
No C#, os nomes que vêm do .NET seguem um padrão: cada palavra começa com maiúscula, inclusive a primeira: Console, WriteLine, ReadLine, ToUpper. Esse estilo se chama PascalCase. As palavras da própria linguagem, como if, int, class e static, são todas minúsculas. A aula Nomes e Convenções conta a regra completa. E um editor de código, como o VS Code, completa os nomes enquanto você digita, já com as maiúsculas certas (aula Editores e IDEs).
Missão: a Ana digitou rápido demais e errou as maiúsculas. Rode, leia cada erro (repare na coluna) e conserte só as letras, até o programa mostrar as duas linhas.
console.WriteLine("Olá, Ana!");
Console.writeLine("Bem-vinda ao C#.");
Console.WriteLine("Olá, Ana!");
Console.WriteLine("Bem-vinda ao C#.");
4. Os sinais e o que cada um faz
Quase todo programa C# usa estes sinais. Cada um tem um papel fixo, e os que abrem ((, {, ") sempre precisam do seu par que fecha:
| Sinal | Nome | Para que serve | Exemplo |
|---|---|---|---|
; | ponto e vírgula | Termina uma instrução | Console.WriteLine("Oi"); |
( ) | parênteses | Chamam um método e levam o que ele recebe; também agrupam contas | WriteLine("Oi"), (2 + 3) * 4 |
" " | aspas duplas | Marcam um texto (string) | "Olá, Ana!" |
' ' | aspas simples | Marcam um caractere (char) | 'A' (aula char e bool) |
. | ponto | "De dentro de": acessa algo que mora dentro de outra coisa | Console.WriteLine |
{ } | chaves | Começam e terminam um bloco | { Console.WriteLine("Oi"); } |
// | barras | Começam um comentário: o resto da linha é ignorado | // isto não roda (aula Comentários) |
Esquecer o par é um dos erros mais comuns. Com o ) faltando:
$ dotnet run parenteses.cs « Console.WriteLine("Olá!";
/home/ana/cs/sintaxe/parenteses.cs(1,25): error CS1026: ) esperado
Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
E sem os parênteses, o compilador nem percebe que você quis chamar o método. Ele acha que a instrução acabou no WriteLine e reclama do ;:
$ dotnet run semparen.cs « Console.WriteLine "Olá!"; /home/ana/cs/sintaxe/semparen.cs(1,19): error CS1002: ; esperado Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
É um bom exemplo de que o compilador diz o que ele esperava encontrar naquele ponto, e não necessariamente o que você esqueceu. O conserto é Console.WriteLine("Olá!");, com parênteses.
Aspas retas, sempre
Copiar código de um PDF, de uma apresentação ou de um processador de texto (Word, Google Docs) pode trazer as aspas curvas, "bonitas" (“ ”), no lugar das retas ("). Para o compilador, elas não são aspas:
Console.WriteLine(“Olá!”);
$ dotnet run curvas.cs /home/ana/cs/sintaxe/curvas.cs(1,19): error CS1056: Caractere inesperado '“' /home/ana/cs/sintaxe/curvas.cs(1,24): error CS1056: Caractere inesperado '”' Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
"Caractere inesperado" (Unexpected character): troque as aspas curvas pelas retas, digitando-as no editor de código.
5. Blocos, recuo e o estilo das chaves
Um bloco é um grupo de instruções entre chaves { }. Ele aparece sempre que várias instruções andam juntas: o corpo de um Main (aula Program.cs e o Main), os passos de um if ("se"), de uma repetição. Aqui as duas mensagens só aparecem se a idade for 18 ou mais (o int idade = 20; cria uma variável, assunto de Variáveis, e o if tem aula própria, if e else; por enquanto, leia como uma frase):
int idade = 20;
if (idade >= 18)
{
Console.WriteLine("Pode tirar a carteira.");
Console.WriteLine("Parabéns!");
}
Console.WriteLine("Fim.");
$ dotnet run bloco.cs Pode tirar a carteira. Parabéns! Fim.
- if (idade >= 18)
- "Se a idade for maior ou igual a 18". Repare: não tem
;no fim. Oifnão é uma instrução completa sozinho: ele "abraça" o bloco que vem logo depois. - {
- Abre o bloco. Ela fica sozinha na linha, alinhada com o
if: é o estilo do C#. - Console.WriteLine(…);
- As instruções de dentro do bloco, com recuo de 4 espaços.
- }
- Fecha o bloco, alinhada com a
{. Depois da}também não vai;. - Console.WriteLine("Fim.");
- Fora do bloco (sem recuo): roda sempre, qualquer que seja a idade.
O recuo é para você, não para o compilador
Recuo (ou indentação, do inglês indentation) são os espaços no começo da linha. O compilador ignora o recuo; quem decide o que está dentro do bloco são as chaves. Este programa, todo torto, compila e roda igual:
int idade = 20;
if (idade >= 18) {
Console.WriteLine("Pode tirar a carteira.");
Console.WriteLine("Parabéns!");
}
$ dotnet run torto.cs Pode tirar a carteira. Parabéns!
Funciona, mas olhe para ele de novo: não dá para ver de relance o que está dentro do if. Num programa de cem linhas, recuo bagunçado é a receita para se perder. A convenção do C# é:
- 4 espaços de recuo a cada bloco (e não tabulação);
- a
{numa linha própria, alinhada com a linha de cima, e a}alinhada com ela. Esse estilo tem nome, Allman. Em Java e JavaScript, o costume é deixar a{no fim da linha, como notorto.cs; o C# aceita os dois, mas quase todo código C# usa o Allman.
Arrumar sozinho: dotnet format
Num projeto (aula Projetos), o comando dotnet format reescreve o código no estilo padrão. A Ana copiou o torto.cs para o Program.cs de um projeto:
$ dotnet format
$ cat Program.cs
int idade = 20;
if (idade >= 18)
{
Console.WriteLine("Pode tirar a carteira.");
Console.WriteLine("Parabéns!");
}
Silêncio quer dizer sucesso: o dotnet format não mostrou nada, só arrumou. O recuo ficou com 4 espaços e a { desceu para a linha dela. Os editores fazem o mesmo com um atalho (no VS Code do Linux, Ctrl+Shift+I; no Windows, Shift+Alt+F).
Chave que não fecha
int idade = 20;
if (idade >= 18)
{
Console.WriteLine("Pode tirar a carteira.");
$ dotnet run chave.cs /home/ana/cs/sintaxe/chave.cs(4,49): error CS1513: } esperada Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O arquivo acabou com o bloco ainda aberto. O compilador aponta o lugar onde percebeu: o fim da linha 4, coluna 49, onde esperava a }. Em inglês: } expected. Num programa grande, a chave que falta pode estar bem longe desse ponto; o recuo bem-feito é o que permite achá-la, porque cada } fica embaixo da sua {.
6. Instrução e expressão
Duas palavras aparecem o tempo todo em livros e mensagens de erro:
- Uma expressão é um pedaço de código que produz um valor:
2 + 3(vale 5),"Olá"(vale o texto Olá). - Uma instrução é uma ordem completa, que faz alguma coisa:
Console.WriteLine(2 + 3);.
As expressões aparecem dentro das instruções. Os parênteses do WriteLine recebem uma expressão, calculam o valor dela e escrevem o resultado:
Console.WriteLine(2 + 3);
Console.WriteLine("2 + 3");
$ dotnet run conta.cs 5 « sem aspas: o C# fez a conta 2 + 3 « com aspas: é só um texto
Uma expressão sozinha, sem fazer nada com o valor, não é uma instrução válida. Escrever só 2 + 3; é como dizer "dois mais três." a alguém, sem pedir nada:
$ dotnet run solta.cs « 2 + 3; /home/ana/cs/sintaxe/solta.cs(1,1): error CS0201: Somente as expressões de atribuição, chamada, incremento, diminuição, espera e novo objeto podem ser utilizadas como uma instrução Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
A lista da mensagem são as expressões que fazem algo e por isso podem virar instrução: guardar um valor (atribuição, x = 5;), chamar um método (Console.WriteLine(…);), somar ou tirar 1 (x++;), esperar (await) e criar um objeto (new). Você vai conhecer cada uma ao longo do guia. Em inglês: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement.
7. Palavras reservadas
Algumas palavras pertencem à própria linguagem e têm um significado fixo: são as palavras-chave (keywords). Você já viu várias: if, int, class, static, void, namespace, using, return. Elas são sempre minúsculas e não podem ser usadas como nome de uma variável sua. Os editores as pintam de uma cor diferente. A lista completa, e o que fazer quando você quer muito um nome como class, está em Nomes e Convenções.
Quando dá errado
error CS1002: ; esperado
O que significa: faltou o ponto e vírgula no fim de uma instrução, ou o compilador achou que a instrução acabou antes do que você imaginava (como no Console.WriteLine "Olá!";, sem parênteses).
Como consertar: vá até a linha e a coluna da mensagem. Se o ; estiver lá, confira os parênteses e as aspas da mesma linha.
error CS0103: O nome "…" não existe no contexto atual
O que significa: um nome escrito errado: maiúscula trocada (console), letra faltando (Consle), ou uma variável usada antes de ser criada (aula Variáveis).
Como consertar: copie o nome da mensagem e compare letra por letra com o certo, inclusive maiúsculas.
error CS0117: "Console" não contém uma definição para "…"
O que significa: o nome antes do ponto existe, mas o que vem depois dele não: Console.writeline, Console.Writeline, Console.PrintLine.
Como consertar: escreva o nome exato, em PascalCase: WriteLine.
error CS1010: Newline em constante
O que significa: um texto entre aspas não foi fechado antes do fim da linha: a aspa de fechamento foi esquecida, ou o texto foi quebrado em duas linhas. Costuma vir acompanhado de vários outros erros.
Como consertar: feche as aspas na mesma linha. Os editores pintam o texto de uma cor só até as aspas fecharem, o que ajuda a enxergar onde ele termina.
error CS1513: } esperada / error CS1026: ) esperado
O que significa: um par ficou sem o sinal de fechamento. A posição indica onde o compilador desistiu de esperar, que pode ser bem longe de onde o par foi aberto.
Como consertar: conte os pares. Com o recuo certo (ou depois de um dotnet format), a { sem par salta aos olhos. Uma } sobrando dá outro erro, que aparece na aula Lendo Erros do Compilador.
error CS1056: Caractere inesperado '“'
O que significa: há um caractere que não faz parte da linguagem, quase sempre aspas curvas copiadas de um documento.
Como consertar: apague as aspas e digite-as de novo no editor de código.
Referência rápida
| Regra | Certo | Errado |
|---|---|---|
Instrução termina com ; | Console.WriteLine("Oi"); | Console.WriteLine("Oi") |
| As instruções rodam de cima para baixo | a linha 1 antes da 2 | (não há como pular, a não ser com if, laços e métodos) |
| Maiúsculas importam | Console.WriteLine | console.writeline |
| Texto entre aspas duplas retas, numa linha só | "Olá, Ana!" | “Olá”, 'Olá', texto quebrado em duas linhas |
| Espaços e quebras de linha entre as palavras são livres | Console.WriteLine( "Oi" ); | Con sole.WriteLine("Oi"); |
| Todo par fecha | ( ), { }, " " | WriteLine("Oi"; |
Bloco entre chaves, sem ; depois da } | { … } | |
| Estilo do C# | 4 espaços de recuo, { na linha própria (Allman) | recuo bagunçado (compila, mas confunde) |
| Uma instrução por linha | duas linhas, dois WriteLine | (compila, mas é difícil de ler) |
Exercícios
1. O fim da instrução
Complete o sinal que falta para a instrução ficar completa:
2. As maiúsculas
Escreva o nome do método com as maiúsculas certas:
3. O erro
Qual é o código do erro "O nome "console" não existe no contexto atual"?
4. O que mostra Console.WriteLine(4 + 4);?
5. A Ana escreveu um programa todo sem recuo, com todas as chaves certas. O que acontece?
6. Qual destas linhas está certa?
7. O compilador mostrou seis erros, e o primeiro é CS1010: Newline em constante. O que fazer?
Missão final: o cardápio
Missão: o cardápio da lanchonete da Ana tem três erros de sintaxe: uma maiúscula, um ponto e vírgula e um parêntese. Use o método: rode, conserte só o primeiro erro, rode de novo. No fim, o programa deve mostrar:
Cardápio da Ana Suco: R$ 6 Pastel: R$ 8
Console.Writeline("Cardápio da Ana");
Console.WriteLine("Suco: R$ 6")
Console.WriteLine("Pastel: R$ 8";
Console.WriteLine("Cardápio da Ana");
Console.WriteLine("Suco: R$ 6");
Console.WriteLine("Pastel: R$ 8");
Repare numa coisa curiosa. O compilador trabalha em etapas: primeiro confere a escrita (sinais, pares, ;) e depois os nomes. No terminal, o dotnet run para na primeira etapa quando ela tem erro: com este código, ele mostra só dois erros (CS1002 na linha 2 e CS1026 na linha 3), e o Writeline da linha 1 só é denunciado (CS0117) depois que você conserta os outros dois:
$ dotnet run cardapio.cs /home/ana/cs/sintaxe/cardapio.cs(2,32): error CS1002: ; esperado /home/ana/cs/sintaxe/cardapio.cs(3,33): error CS1026: ) esperado Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O editor do guia trabalha nas mesmas etapas e mostra os mesmos dois erros; o CS0117 só aparece lá também depois do conserto dos outros. A lição: um erro pode esconder outro, então compile de novo depois de cada conserto.
Resumo
- Sintaxe são as regras de escrita da linguagem. O compilador não aceita nenhum desvio.
- Uma instrução é uma ordem completa e termina com
;. As instruções rodam de cima para baixo. Use uma por linha. - Espaços e quebras de linha entre as palavras são livres, mas não dentro de um nome nem dentro de um texto entre aspas (
CS1010). - O C# diferencia maiúsculas de minúsculas:
Console.WriteLine, nuncaconsole.writeline(CS0103,CS0117). ( )chamam métodos," "marcam textos (aspas retas:CS1056),.é "de dentro de",{ }formam blocos. Todo par fecha (CS1026,CS1513).- O recuo é para as pessoas: o padrão do C# é 4 espaços e a
{na linha própria (estilo Allman).dotnet formatarruma um projeto. - Uma expressão produz um valor (
2 + 3); sozinha, ela não é uma instrução (CS0201).