C# Ler do Teclado (Console.ReadLine)

Até aqui, todo programa da Ana fazia sempre a mesma coisa: os valores estavam escritos no código. Para fazer uma calculadora, um jogo ou um cadastro, o programa precisa perguntar e esperar a resposta de quem está usando. Em C#, quem faz isso é o Console.ReadLine() ("ler linha do console"): ele para o programa, espera a pessoa digitar e apertar Enter, e entrega o que foi digitado como texto. Nesta aula você vai ver como usá-lo, por que o compilador avisa que a resposta "pode ser nula", e como transformar o texto em número sem o programa quebrar.

Você vai aprender
  • Como ler uma linha com Console.ReadLine() e mostrar uma pergunta antes com Console.Write.
  • Por que o resultado é string? e quando ele vale null.
  • Os avisos reais CS8600, CS8602 e CS8604, e o que acontece quando você os ignora.
  • Três jeitos de tratar o null: is null, ?? e Trim para respostas vazias.
  • Como ler números com int.TryParse e decimal.TryParse, e por que o Parse derruba o programa.
  • A pegadinha do ponto e da vírgula: por que 3.50 virou 315,00.
  • Como ler várias linhas num laço e mandar a entrada de um arquivo, com <.

Todos os programas foram rodados com o .NET 10 (dotnet --version = 10.0.112, C# 14) na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/cs, com dotnet run arquivo.cs. Nos terminais, o que vem depois de uma pergunta (como Ana em Qual é o seu nome? Ana) foi digitado pela Ana. Antes desta aula, é bom ter visto Texto → Número (Parse e TryParse).


A ideia: o atendente do balcão

Pense num atendente de padaria. Ele pergunta "o que vai ser?" e espera. Não adianta ele adivinhar: só continua quando você responde. E ele anota a resposta do jeito que ouviu, como palavras: se você disser "dois pães", ele anota as palavras "dois pães", e ainda precisa entender que "dois" é o número 2.

  • O Console.Write("O que vai ser? ") é a pergunta.
  • O Console.ReadLine() é a espera: o programa fica parado até a pessoa apertar Enter.
  • O que ele devolve é sempre texto (string), mesmo que a pessoa tenha digitado 29. Transformar em número é outro passo.
  • E às vezes o cliente vai embora sem responder. No programa, isso é o null: "não veio resposta nenhuma".

1. A primeira leitura

Console.Write("Qual é o seu nome? ");
string? nome = Console.ReadLine();
Console.WriteLine($"Olá, {nome}!");
Console.Write("Qual é o seu nome? ");
A pergunta. Com Write (e não WriteLine), o cursor fica na mesma linha, logo depois do espaço, e a resposta aparece ao lado da pergunta. É o jeito mais comum. O espaço no fim do texto separa a pergunta da resposta.
Console.ReadLine()
Para o programa e espera. Quando a pessoa aperta Enter, ele devolve tudo o que ela digitou naquela linha, sem o Enter.
string? nome
A variável que guarda a resposta. O tipo é string?, "texto ou null". O ? é o assunto da seção 2.
$"Olá, {nome}!"
Usa a resposta, como qualquer outra variável.
$ dotnet run le.cs
Qual é o seu nome? Ana          « a Ana digita Ana e aperta Enter
Olá, Ana!

Enquanto a Ana não aperta Enter, o programa fica esperando, para sempre se for preciso. Ela pode apagar e corrigir à vontade: o ReadLine só recebe a linha quando o Enter é apertado.

No editor do guia

Nas caixas "Experimente", o programa pode pedir a entrada: aparece um campo no terminal da caixa, logo depois da pergunta, e você digita e tecla Enter. Ctrl+D é o fim da entrada (o ReadLine devolve null), e Ctrl+C ou o botão Parar interrompe. Por dentro há um truque: o navegador não deixa o programa ficar esperando o teclado, então, a cada Enter, o editor roda o programa de novo, desde o começo, com as linhas que você já digitou. A saída é a mesma; só muda o que depende do relógio, como DateTime.Now (veja O Editor do Guia). Nas missões desta aula, a entrada já vem pronta, escrita na caixa, para o resultado ser sempre o mesmo: é como se alguém tivesse digitado por você.

Missão: o programa lê o nome, mas não o usa. A entrada desta caixa é Bia. Troque a mensagem para Olá, Bia! Bem-vinda à lojinha., usando a variável nome (não escreva "Bia" no código: o programa tem de funcionar para qualquer nome).

Qual é o seu nome? Olá, Bia! Bem-vinda à lojinha.
Console.Write("Qual é o seu nome? ");
string? nome = Console.ReadLine();
Console.WriteLine("Olá! Bem-vinda à lojinha.");
Console.Write("Qual é o seu nome? ");
string? nome = Console.ReadLine();
Console.WriteLine($"Olá, {nome}! Bem-vinda à lojinha.");

2. Por que string?: quando a entrada acaba

O ReadLine pode devolver uma coisa que não é texto nenhum: null, que quer dizer "nada" (aula null e Tipos Anuláveis). Isso acontece quando a entrada acabou e não há mais linha para ler. Não é o mesmo que uma resposta vazia: se a pessoa só aperta Enter, chega "", um texto com zero letras. O null é "não veio linha".

Quando a entrada acaba?

  • No terminal, quando a pessoa aperta Ctrl+D (no Linux e no macOS; no Windows é Ctrl+Z e Enter). É o sinal de "fim da entrada".
  • Quando a entrada vem de um arquivo (seção 6) e as linhas do arquivo terminaram.
  • Quando o programa roda sem ninguém para digitar, como num servidor.

Por isso o C# diz que o ReadLine devolve string? e não string. Como o guia usa as referências anuláveis (ligadas por padrão no .NET 10, aula Referências Anuláveis), o compilador confere se você está preparado para esse null. Veja o que acontece se a Ana escrever só string, sem o ?:

Console.Write("Qual é o seu nome? ");
string nome = Console.ReadLine();
Console.WriteLine($"Olá, {nome}! Seu nome tem {nome.Length} letras.");
$ dotnet run aviso.cs
/home/ana/cs/aviso.cs(2,15): warning CS8600: Conversão de literal nula ou possível valor nulo em tipo não anulável.
/home/ana/cs/aviso.cs(3,48): warning CS8602: Desreferência de uma referência possivelmente nula.
Qual é o seu nome? Ana
Olá, Ana! Seu nome tem 3 letras.
warning
São avisos, não erros: o programa compilou e rodou (aula Avisos do Compilador). Eles aparecem só quando o arquivo é compilado; se você rodar de novo sem mudar nada, o dotnet reaproveita a compilação e não os mostra outra vez. Não é porque sumiram. (O editor do guia compila a cada Rodar, então mostra os avisos sempre.)
CS8600 (linha 2, coluna 15)
"Conversão de um possível valor nulo em tipo não anulável": o ReadLine() pode dar null, e você está guardando numa string, que promete nunca ser null. Em inglês: Converting null literal or possible null value to non-nullable type.
CS8602 (linha 3, coluna 48)
"Desreferência de uma referência possivelmente nula": o nome.Length pede o tamanho de algo que pode ser null. "Desreferenciar" é usar o ponto (.) para pegar alguma coisa de dentro de um objeto. Em inglês: Dereference of a possibly null reference.

Com a Ana digitando, tudo funcionou. Mas o aviso não é exagero. Veja o mesmo programa quando a entrada acaba: o < /dev/null manda para o programa uma entrada vazia, que acaba logo de cara, como se a Ana apertasse Ctrl+D antes de digitar qualquer coisa:

$ dotnet run aviso.cs < /dev/null
Qual é o seu nome? Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at Program.<Main>$(String[] args) in /home/ana/cs/aviso.cs:line 3
$ echo $?
134

Unhandled exception = "exceção não tratada": o programa quebrou. NullReferenceException é a exceção de "usar um null como se fosse um objeto": Object reference not set to an instance of an object, "a referência não aponta para nenhum objeto". A linha culpada é a 3, o nome.Length, exatamente onde o CS8602 avisou. O código de saída 134 é o de um programa que terminou com exceção (aula Exceções).

Regra do guia: leia com string? e trate o null

Guarde a resposta do ReadLine() numa string? e decida o que fazer quando ela for null, com um dos jeitos da próxima seção. Nunca "cale" o aviso sem pensar: ele está apontando um jeito real de o programa quebrar.


3. Três jeitos de tratar o null

Jeito 1: perguntar com is null

Console.Write("Qual é o seu nome? ");
string? nome = Console.ReadLine();
if (nome is null)
{
    Console.WriteLine();
    Console.WriteLine("A entrada acabou: ninguém digitou nada.");
}
else
{
    Console.WriteLine($"Olá, {nome}!");
}
$ dotnet run nulo.cs
Qual é o seu nome?              « a Ana aperta Ctrl+D (nada aparece na tela)
A entrada acabou: ninguém digitou nada.
nome is null
"nome é nulo?". Dentro do else, o compilador sabe que nome não é null, e não avisa mais nada se você usar nome.Length ali. (Também dá para escrever nome == null; o is null é o jeito preferido no C# moderno.)
Console.WriteLine();
Como a Ana não apertou Enter, o cursor ficou ao lado da pergunta. Esta linha vazia pula para a linha de baixo antes da mensagem.

Jeito 2: um valor no lugar, com ??

Muitas vezes, "a entrada acabou" e "a pessoa não digitou nada" podem ter o mesmo tratamento. O operador ?? ("se for nulo, use isto", aula Operadores ??, ?. e ??=) troca o null por um texto vazio já na leitura. Aí a variável pode ser uma string comum, sem ? e sem aviso:

Console.Write("Qual é o seu nome? ");
string nome = Console.ReadLine() ?? "";
nome = nome.Trim();
if (nome == "")
{
    nome = "visitante";
}
Console.WriteLine($"Olá, {nome}! Seu nome tem {nome.Length} letras.");
Console.ReadLine() ?? ""
Se o ReadLine devolver um texto, fica o texto. Se devolver null, fica "". O resultado nunca é null, por isso cabe numa string.
nome.Trim()
"Aparar": tira os espaços do começo e do fim (aula Métodos de String). Quem digita muitas vezes deixa um espaço sobrando sem perceber.
if (nome == "")
Depois do Trim, uma resposta só com espaços também vira "". Aqui o programa escolhe um nome padrão.
$ dotnet run vazio.cs
Qual é o seu nome?    Ana       « a Ana digitou espaços antes e depois
Olá, Ana! Seu nome tem 3 letras.
$ dotnet run vazio.cs
Qual é o seu nome?              « a Ana só apertou Enter
Olá, visitante! Seu nome tem 9 letras.

Jeito 3: string.IsNullOrWhiteSpace

Para perguntar tudo de uma vez ("é null, vazio ou só espaços?"), existe string.IsNullOrWhiteSpace(nome) ("é nulo ou espaço em branco"). Ele aparece no laço da seção 6.

E o Console.ReadLine()!?

Você vai ver em muitos exemplos na internet string nome = Console.ReadLine()!;. O ! no fim é o operador "eu garanto que não é nulo" (null-forgiving). Ele só cala o aviso: se a entrada acabar, o NullReferenceException acontece do mesmo jeito. Use ?? ou is null, que resolvem de verdade.


4. Ler números: TryParse, e não Parse

O ReadLine sempre devolve texto. Tentar guardar direto num int nem compila:

$ cat cs0029.cs
Console.Write("Quantos anos você tem? ");
int idade = Console.ReadLine();
Console.WriteLine(idade + 10);
$ dotnet run cs0029.cs
/home/ana/cs/cs0029.cs(2,13): 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.

O texto "29" não é o número 29: é um '2' seguido de um '9'. Para virar número, ele precisa ser convertido. A primeira ideia costuma ser o int.Parse (aula Parse e TryParse):

Console.Write("Quantos anos você tem? ");
int idade = int.Parse(Console.ReadLine());
Console.WriteLine($"Daqui a 10 anos você terá {idade + 10}.");
$ dotnet run idade-parse.cs
/home/ana/cs/idade-parse.cs(2,23): warning CS8604: Possível argumento de referência nula para o parâmetro 's' em 'int int.Parse(string s)'.
Quantos anos você tem? 29
Daqui a 10 anos você terá 39.
$ dotnet run idade-parse.cs
Quantos anos você tem? vinte
Unhandled exception. System.FormatException: The input string 'vinte' was not in a correct format.
   at System.Number.ThrowFormatException[TChar](ReadOnlySpan`1 value)
   at System.Int32.Parse(String s)
   at Program.<Main>$(String[] args) in /home/ana/cs/idade-parse.cs:line 2
$ echo $?
134

Dois problemas de uma vez:

  • O aviso CS8604: "possível argumento nulo para o parâmetro s de int.Parse(string s)". O Parse quer uma string de verdade, e o ReadLine() pode dar null. Em inglês: Possible null reference argument for parameter 's'.
  • A exceção FormatException: The input string 'vinte' was not in a correct format, "o texto 'vinte' não está num formato correto". Basta a pessoa digitar uma letra para o programa inteiro cair.

O TryParse ("tentar converter") resolve os dois. Ele aceita null, não lança exceção e diz se deu certo:

Console.Write("Quantos anos você tem? ");
string? texto = Console.ReadLine();
if (int.TryParse(texto, out int idade))
{
    Console.WriteLine($"Daqui a 10 anos você terá {idade + 10}.");
}
else
{
    Console.WriteLine($"\"{texto}\" não é um número inteiro.");
}
string? texto = Console.ReadLine();
Primeiro, guarda o texto do jeito que veio, com ?.
int.TryParse(texto, out int idade)
Tenta converter. Se conseguir, devolve true e põe o número em idade. Se não conseguir (letras, vazio ou null), devolve false e idade fica 0. O out int idade cria a variável ali mesmo (aula ref, out e in).
if (…) { … } else { … }
O programa decide o que fazer nos dois casos, em vez de quebrar.
\"{texto}\"
O \" põe aspas dentro do texto (aula Escapes), para mostrar exatamente o que a pessoa digitou.
$ dotnet run idade.cs                  « compilou sem nenhum aviso
Quantos anos você tem? vinte
"vinte" não é um número inteiro.
$ dotnet run idade.cs
Quantos anos você tem? 29
Daqui a 10 anos você terá 39.

Missão: a entrada desta caixa é vinte. Rode: o int.Parse derruba o programa com FormatException e código de saída 134. Troque-o por int.TryParse para que o programa mostre "vinte" não é um número inteiro. e termine normalmente (código 0).

Quantos anos você tem? "vinte" não é um número inteiro.
Console.Write("Quantos anos você tem? ");
string? texto = Console.ReadLine();
int idade = int.Parse(texto);
Console.WriteLine($"Daqui a 10 anos você terá {idade + 10}.");
Console.Write("Quantos anos você tem? ");
string? texto = Console.ReadLine();
if (int.TryParse(texto, out int idade))
{
    Console.WriteLine($"Daqui a 10 anos você terá {idade + 10}.");
}
else
{
    Console.WriteLine($"\"{texto}\" não é um número inteiro.");
}

Perguntar de novo até vir um número

Em vez de desistir na primeira resposta errada, o programa pode repetir a pergunta com um laço (aula do while):

int idade;
string? texto;
do
{
    Console.Write("Quantos anos você tem? ");
    texto = Console.ReadLine();
    if (texto is null)
    {
        return;
    }
} while (!int.TryParse(texto, out idade));
Console.WriteLine($"Daqui a 10 anos você terá {idade + 10}.");
while (!int.TryParse(texto, out idade))
Repete enquanto não conseguir converter. Quando conseguir, sai do laço com o número em idade.
if (texto is null) { return; }
Se a entrada acabar, não adianta perguntar de novo: nenhuma resposta vai chegar, e o laço ficaria infinito. O return, no programa de nível superior, termina o programa.
$ dotnet run insiste.cs
Quantos anos você tem? vinte
Quantos anos você tem?          « a Ana só apertou Enter
Quantos anos você tem? 29
Daqui a 10 anos você terá 39.

5. Vírgula ou ponto? A pegadinha do pt-BR

Para preços e notas com casas decimais, use decimal.TryParse (ou double.TryParse). Ele converte do jeito do idioma do computador. No notebook da Ana, em português do Brasil, a vírgula separa os centavos e o ponto separa os milhares, como em R$ 1.234,50 (aula Cultura). Veja o que acontece com cada resposta:

Console.Write("Preço: ");
string? texto = Console.ReadLine();
if (decimal.TryParse(texto, out decimal preco))
{
    Console.WriteLine($"Com 10% de desconto: {preco * 0.9m:C}");
}
else
{
    Console.WriteLine("Preço inválido.");
}
$ dotnet run preco.cs
Preço: 3,50
Com 10% de desconto: R$ 3,15
$ dotnet run preco.cs
Preço: 3.50
Com 10% de desconto: R$ 315,00      « !!! o ponto foi lido como separador de milhar
$ dotnet run preco.cs
Preço: 1.234,50
Com 10% de desconto: R$ 1.111,05
$ dotnet run preco.cs
Preço: abc
Preço inválido.
A Ana digitouO decimal.TryParse entendeu (pt-BR)Por quê
3,503,50A vírgula é a casa decimal.
3.50350O ponto é separador de milhar, e o TryParse o ignora. Deu true, sem erro nenhum.
1.234,501234,50Milhar com ponto e centavos com vírgula: o jeito brasileiro completo.
abc(falhou)Não é número: devolve false.

O 3.50 é o caso perigoso: o programa não quebra nem reclama, só calcula errado. Num computador em inglês, seria o contrário: 3.50 daria 3,50 e 3,50 daria 350. Por isso:

  • diga na pergunta o formato que você espera: Console.Write("Preço (ex.: 12,90): ");;
  • quando o número vem de um arquivo ou de outro programa, e não de uma pessoa, leia com uma cultura fixa (CultureInfo.InvariantCulture), assunto da aula Cultura.

6. Várias linhas: ler num laço

A Ana quer somar os preços de uma compra, sem saber quantos itens são. O programa lê uma linha por volta e para quando ela aperta Enter numa linha vazia, ou quando a entrada acaba:

decimal total = 0m;
int itens = 0;
Console.WriteLine("Digite os preços (Enter numa linha vazia termina):");
while (true)
{
    string? linha = Console.ReadLine();
    if (string.IsNullOrWhiteSpace(linha))
    {
        break;
    }
    if (decimal.TryParse(linha, out decimal preco))
    {
        total += preco;
        itens++;
    }
    else
    {
        Console.WriteLine($"Ignorado: \"{linha}\" não é um preço.");
    }
}
Console.WriteLine($"{itens} itens, total {total:C}");
while (true)
Um laço "para sempre", que só termina pelo break (aula break e continue).
string? linha = Console.ReadLine();
Uma leitura por volta. Cada volta espera uma linha nova.
string.IsNullOrWhiteSpace(linha)
Verdade se a linha for null (a entrada acabou), vazia ou só espaços. Nos três casos, o laço termina.
decimal.TryParse(…)
Se for um preço, soma. Se não for, avisa e continua: um erro de digitação não perde a compra inteira.
{total:C}
O formato de moeda: R$ 24,40 no pt-BR (aula Formatar Números).
$ dotnet run soma.cs
Digite os preços (Enter numa linha vazia termina):
12,90
4,50
dez
Ignorado: "dez" não é um preço.
7
                    « linha vazia: a Ana só apertou Enter
3 itens, total R$ 24,40

A entrada vinda de um arquivo

O ReadLine lê da entrada padrão, que normalmente é o teclado. No terminal, o < troca o teclado por um arquivo (é o mesmo < do Guia Bash). Cada linha do arquivo vira uma resposta, e quando o arquivo acaba, o ReadLine devolve null:

$ cat precos.txt
12,90
4,50
dez
7
$ dotnet run soma.cs < precos.txt
Digite os preços (Enter numa linha vazia termina):
Ignorado: "dez" não é um preço.
3 itens, total R$ 24,40

Repare que os preços não aparecem na tela: eles não foram digitados, então o terminal não os mostrou. Só aparece o que o programa escreveu. O arquivo não tem linha vazia no fim: quem parou o laço foi o null do fim da entrada. É por isso que tratar o null importa: sem ele, este laço quebraria (ou nunca terminaria) com um arquivo.


7. Outras formas de ler, e qual usar

FormaO que fazQuando usar
Console.ReadLine()Espera o Enter e devolve a linha inteira (string?).Quase sempre: nomes, números, opções de menu.
Console.ReadKey()Devolve uma tecla assim que ela é apertada, sem esperar o Enter.Jogos e menus de uma tecla, como "aperte qualquer tecla para continuar". Só funciona com um teclado de verdade: com a entrada vindo de um arquivo, ele lança InvalidOperationException.
Console.Read()Lê um caractere e devolve o código dele como int (−1 no fim da entrada).Raramente. Ele também espera o Enter, e o próprio Enter vira um caractere lido depois.
Console.In.ReadToEnd()Lê tudo, até o fim da entrada, de uma vez.Programas que recebem um arquivo pelo < e processam tudo junto.

E para converter o que foi lido:

FormaCom texto inválidoCom nullUse?
int.TryParse(texto, out int n)devolve falsedevolve falseSim: é o certo para entrada de pessoas.
int.Parse(texto)FormatExceptionArgumentNullException e o aviso CS8604Só quando o texto com certeza é um número (que o próprio programa gerou).
Convert.ToInt32(texto)FormatExceptiondevolve 0, caladoEvite com entrada do usuário: um null vira 0 sem você perceber.

Quando dá errado

warning CS8600: Conversão de literal nula ou possível valor nulo em tipo não anulável.

O que significa: você guardou Console.ReadLine() numa string sem ?. Se a entrada acabar, ela vai receber null, que uma string promete não ter.

Como consertar: use string? nome = Console.ReadLine(); e trate o null com is null, ou troque por um valor: string nome = Console.ReadLine() ?? "";.

warning CS8602: Desreferência de uma referência possivelmente nula.

O que significa: você usou um ponto (nome.Length, nome.Trim()) numa variável que pode ser null. Se ela for, o programa quebra com NullReferenceException nessa linha.

Como consertar: confira antes (if (nome is not null)), ou garanta um valor na leitura com ?? "".

warning CS8604: Possível argumento de referência nula para o parâmetro 's' em 'int int.Parse(string s)'.

O que significa: o int.Parse(Console.ReadLine()) passa um possível null para um método que não aceita null.

Como consertar: use int.TryParse(texto, out int n), que aceita null (e devolve false).

error CS0029: Não é possível converter implicitamente tipo "string" em "int"

O que significa: você escreveu int idade = Console.ReadLine();. O ReadLine devolve texto, e texto não vira número sozinho.

Como consertar: leia numa string? e converta com int.TryParse.

Unhandled exception. System.FormatException: The input string 'vinte' was not in a correct format.

O que significa: o int.Parse (ou decimal.Parse) recebeu um texto que não é número, e o programa terminou com o código 134.

Como consertar: troque por TryParse num if, e diga ao usuário o que deu errado (ou pergunte de novo).

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.

O que significa: a entrada acabou (Ctrl+D, ou o fim do arquivo do <), o ReadLine devolveu null, e o programa usou esse null com um ponto. Era o que os avisos CS8600 e CS8602 diziam.

Como consertar: não ignore os avisos de nulo: siga a seção 3.

A conta deu 100 vezes mais (3.50 virou 350)

O que significa: no pt-BR, o ponto é separador de milhar, e o decimal.TryParse o ignora sem reclamar.

Como consertar: peça o formato na pergunta ("Preço (ex.: 12,90): "). Para dados de arquivos, use CultureInfo.InvariantCulture (aula Cultura).

O programa "travou" e não mostra nada

O que significa: provavelmente ele está parado num ReadLine, esperando você digitar, e faltou um Console.Write com a pergunta antes.

Como consertar: sempre escreva a pergunta antes de ler. Para sair de um programa que espera entrada, aperte Ctrl+D (fim da entrada) ou Ctrl+C (interromper).


Referência rápida

EscritaO que faz
Console.Write("Nome: ");Mostra a pergunta e deixa o cursor na mesma linha
string? s = Console.ReadLine();Lê uma linha (sem o Enter); null se a entrada acabou
string s = Console.ReadLine() ?? "";Lê, trocando o null por texto vazio
if (s is null)Confere se a entrada acabou
s.Trim()Tira os espaços do começo e do fim
string.IsNullOrWhiteSpace(s)Nulo, vazio ou só espaços?
int.TryParse(s, out int n)Converte para inteiro; true se deu certo
decimal.TryParse(s, out decimal d)Converte para decimal, com a vírgula do pt-BR
while (true) { … ReadLine … break; }Lê várias linhas até uma condição
dotnet run prog.cs < arquivo.txtManda as linhas do arquivo como entrada
Ctrl+D (Linux, macOS) / Ctrl+Z e Enter (Windows)Fim da entrada: o ReadLine devolve null

Exercícios

1. O tipo certo

Complete o tipo da variável para não ter nenhum aviso:

cidade = Console.ReadLine();

2. Sem null

Complete para trocar o null por um texto vazio:

string cidade = Console.ReadLine() ;

3. Converter sem quebrar

Complete o método que converte texto em int sem lançar exceção:

if (int.(texto, out int quantidade))

4. Quando o Console.ReadLine() devolve null?

5. No notebook da Ana (pt-BR), decimal.TryParse("3.50", out decimal d) deixa d valendo…

6. A pessoa digitou dez e o programa usa int.Parse(texto). O que acontece?

Missão final: a média sem avisos

Missão: o programa lê duas notas e mostra a média. Ele funciona com a entrada desta caixa (7,5 e 9), mas compila com dois avisos CS8604 e quebraria com uma nota digitada errado. Reescreva a leitura com decimal.TryParse: se as duas notas forem válidas, mostre Média: 8,25; se não, mostre Nota inválida.. A missão exige zero avisos.

Primeira nota: Segunda nota: Média: 8,25
Console.Write("Primeira nota: ");
decimal nota1 = decimal.Parse(Console.ReadLine());
Console.Write("Segunda nota: ");
decimal nota2 = decimal.Parse(Console.ReadLine());
Console.WriteLine($"Média: {(nota1 + nota2) / 2}");
Console.Write("Primeira nota: ");
string? texto1 = Console.ReadLine();
Console.Write("Segunda nota: ");
string? texto2 = Console.ReadLine();
if (decimal.TryParse(texto1, out decimal nota1) && decimal.TryParse(texto2, out decimal nota2))
{
    Console.WriteLine($"Média: {(nota1 + nota2) / 2}");
}
else
{
    Console.WriteLine("Nota inválida.");
}

Na solução, as duas leituras vêm primeiro e as duas conversões ficam juntas no if, ligadas por && ("e"): a média só é calculada se as duas derem certo. Experimente mudar a entrada da caixa para 7.5 e 9: com o ponto, a primeira nota vira 75, e a média, 42. É a pegadinha da seção 5.


Resumo

  • Console.ReadLine() para o programa, espera o Enter e devolve a linha digitada como texto. Escreva a pergunta antes com Console.Write.
  • Ele devolve string?: vale null quando a entrada acaba (Ctrl+D, ou o fim de um arquivo mandado com <). Uma linha vazia é "", não null.
  • Os avisos CS8600, CS8602 e CS8604 avisam de um NullReferenceException real. Trate o null com is null, ?? "" ou string.IsNullOrWhiteSpace; não os cale com !.
  • Para números, use int.TryParse e decimal.TryParse num if. O Parse quebra o programa com FormatException quando a pessoa digita errado.
  • No pt-BR, a vírgula é a casa decimal e o ponto é o milhar: 3.50 vira 350 sem erro nenhum. Diga o formato na pergunta.
  • Para várias respostas, leia num laço até uma linha vazia ou até o null do fim da entrada.