Conversão de Tipos: Transformando Texto em Número, com Segurança

Conversão de Tipos: Transformando Texto em Número, com Segurança

Como transformar o texto que o usuário digita em números utilizáveis. A conversão direta com Parse e por que ela quebra o programa diante de uma entrada inválida, e a conversão segura com TryParse, que informa se deu certo em vez de interromper tudo — a base de programas robustos.
Linguagem C#

• • 11 min de leitura

A aula anterior terminou com um problema bem formulado: o usuário digita "30", mas o programa recebe o texto "30", e não o número 30 — e texto não serve para cálculos. Esta aula resolve esse problema e, ao fazê-lo, ensina uma das lições mais importantes de toda a programação: a de que os dados que vêm do mundo exterior não são confiáveis, e um bom programa se prepara para isso. Aprenderemos a converter texto em número de duas maneiras — uma ingênua, que funciona quando tudo dá certo mas quebra o programa quando algo dá errado, e uma robusta, que lida com o inesperado de forma elegante. Ao final, seus programas interativos deixarão de ser frágeis e passarão a resistir a entradas malucas.

Conversão: mudando a natureza de um valor

Converter um valor significa transformá-lo de um tipo em outro — no nosso caso, de string (texto) para int (número inteiro). A conversão não muda o valor no sentido do seu significado; muda a sua natureza, de modo que ele passe a poder ser usado onde aquela natureza é exigida. O texto "30" e o número 30 representam a mesma quantidade aos nossos olhos, mas são coisas diferentes para o computador; a conversão constrói a ponte entre eles.

O C# oferece, para cada tipo numérico, uma ferramenta de conversão a partir de texto. Para o int, a forma mais direta chama-se int.Parse (a palavra inglesa parse significa, aproximadamente, "analisar e interpretar"). Ela recebe um texto e devolve o número correspondente:

string textoIdade = "30";
int idade = int.Parse(textoIdade);   // converte o texto "30" no número 30
Console.WriteLine(idade + 1);         // agora SIM: soma aritmética, resulta 31

Repare no que mudou. Antes, idade era texto e + 1 teria concatenado; agora, após o int.Parse, idade é um número de verdade, e idade + 1 faz a soma aritmética, produzindo 31. A conversão foi a ponte que faltava. Juntando com a leitura da aula anterior, podemos finalmente ler e calcular:

Console.Write("Digite sua idade: ");
string entrada = Console.ReadLine();
int idade = int.Parse(entrada);      // converte o que foi digitado em número
Console.WriteLine("No ano que vem você terá " + (idade + 1) + " anos.");

(Note os parênteses em (idade + 1): eles garantem que a soma aconteça antes da concatenação com o texto. Sem eles, a mistura de soma e concatenação numa mesma linha poderia produzir resultados confusos — os parênteses deixam claro que primeiro se soma, depois se junta ao texto.)

O perigo da conversão ingênua

O programa acima funciona desde que o usuário colabore, digitando um número. Mas — e aqui está a lição central — o usuário nem sempre colabora. Ele pode digitar "trinta", "3o" (com a letra "o" no lugar do zero), deixar em branco, ou digitar qualquer bobagem. O que acontece então? O int.Parse não consegue interpretar aquilo como número, e ele reage da maneira mais drástica possível: ele quebra o programa. O programa é interrompido abruptamente, com uma mensagem de erro técnica, e nada mais do que viria depois é executado.

Essa é uma falha grave de robustez. Um programa que quebra diante de uma digitação errada é frágil e frustrante de usar. E o problema não é culpa do usuário — é responsabilidade nossa, como programadores, antecipar que entradas inválidas acontecerão e preparar o programa para elas. Confiar cegamente que a entrada será sempre válida é o erro número um de quem começa. Precisamos de uma forma de conversão que não quebre quando o texto não for um número, e sim nos avise educadamente que a conversão falhou.

A conversão segura: TryParse

O C# oferece exatamente essa forma segura, chamada int.TryParse (do inglês try, "tentar" — ou seja, "tente interpretar"). Em vez de quebrar quando falha, ela tenta a conversão e nos informa se deu certo ou não, entregando o número convertido separadamente. Sua forma de uso é um pouco diferente e merece explicação cuidadosa:

Console.Write("Digite sua idade: ");
string entrada = Console.ReadLine();

int idade;   // declaramos a variável que receberá o número, se a conversão der certo

if (int.TryParse(entrada, out idade))
{
    Console.WriteLine("No ano que vem você terá " + (idade + 1) + " anos.");
}
else
{
    Console.WriteLine("Isso não parece um número válido.");
}

Há elementos novos aqui, e vamos destrinchá-los, mesmo que alguns só sejam plenamente estudados adiante. O int.TryParse(entrada, out idade) faz duas coisas ao mesmo tempo: tenta converter entrada num número e, se conseguir, coloca esse número na variável idade (é o que a palavra out sinaliza — que idade é uma variável de saída, que a ação vai preencher). Além disso, o TryParse devolve um valor de verdadeiro ou falso (um bool, da Aula #05): verdadeiro se a conversão deu certo, falso se não. Esse verdadeiro/falso é usado pelo if — uma estrutura de decisão que estudaremos em detalhe na próxima fase, mas cuja ideia intuitiva você já capta aqui: se a conversão deu certo, execute o primeiro bloco; senão (else), execute o segundo. Assim, digitar "trinta" não quebra mais nada — apenas cai no else, exibindo a mensagem de erro amigável.

Não se preocupe se o if/else e o out ainda parecerem um tanto misteriosos; eles serão aprofundados nas aulas seguintes. O que importa absorver agora é a diferença de filosofia entre as duas conversões: o int.Parse diz "confie em mim, isto é um número", e explode se estiver errado; o int.TryParse diz "vamos tentar, e eu te aviso se não der certo", permitindo que o programa reaja com elegância. Para qualquer dado vindo de um usuário, a escolha certa é quase sempre o TryParse.

Convertendo para outros tipos

O mesmo par de ferramentas existe para os outros tipos numéricos. Para converter texto em um número com casas decimais, há double.Parse e double.TryParse; para dinheiro, decimal.Parse e decimal.TryParse. Todos funcionam da mesma maneira, mudando apenas o tipo de destino:

Console.Write("Digite o preço: ");
string entrada = Console.ReadLine();
if (decimal.TryParse(entrada, out decimal preco))
{
    Console.WriteLine("Com 10% de desconto: " + (preco * 0.9m));
}
else
{
    Console.WriteLine("Preço inválido.");
}

(Repare que, aqui, declaramos a variável diretamente dentro do TryParse, escrevendo out decimal preco — uma forma abreviada e comum de fazer as duas coisas de uma vez: declarar a variável e recebê-la preenchida. As duas formas, declarar antes ou ali mesmo, são válidas.)

A regra geral a levar desta aula: sempre que precisar transformar o texto digitado por um usuário em um número, prefira a versão TryParse, que protege seu programa contra entradas inválidas. A versão Parse tem seu lugar — quando você tem certeza de que o texto é um número válido, por exemplo, um valor que veio de dentro do próprio programa —, mas para dados do mundo exterior, a segurança do TryParse vale cada caractere a mais que ela custa.

O mistério deixado pela entrada de dados está resolvido. Você sabe converter texto em número, conhece a forma direta com Parse e entende por que ela é perigosa: diante de uma entrada que não representa um número, o programa não avisa nem contorna — ele quebra.

A alternativa madura é TryParse, que devolve se a conversão deu certo em vez de interromper tudo, permitindo ao programa reagir com uma mensagem clara. Essa diferença entre falhar ruidosamente e tratar o erro com elegância é um dos primeiros sinais de código profissional, e ela aparece muito além da conversão de tipos.

Fontes e leituras recomendadas

Exercícios

Exercício 1

Escreva um programa que peça um número ao usuário, converta-o com int.Parse, e exiba o dobro dele. Teste digitando um número válido e confirme que funciona. Depois, teste digitando "abc" e observe o que acontece — descreva o comportamento do programa.

Ver resposta

✓ Resposta: Exemplo:

Console.Write("Digite um número: ");
int n = int.Parse(Console.ReadLine());
Console.WriteLine("O dobro é: " + (n * 2));

Com um número válido, o programa exibe o dobro corretamente. Ao digitar "abc", o int.Parse não consegue interpretar o texto como número e o programa quebra: a execução é interrompida abruptamente com uma mensagem de erro técnica, e a linha que exibiria o dobro nunca chega a rodar. Isso demonstra a fragilidade da conversão ingênua diante de entrada inválida.

Exercício 2

Reescreva o programa do exercício anterior usando int.TryParse, de modo que, se o usuário digitar algo que não seja um número, o programa exiba uma mensagem de erro amigável em vez de quebrar. Teste com uma entrada válida e uma inválida.

Ver resposta

✓ Resposta: Exemplo:

Console.Write("Digite um número: ");
string entrada = Console.ReadLine();
if (int.TryParse(entrada, out int n))
    Console.WriteLine("O dobro é: " + (n * 2));
else
    Console.WriteLine("Isso não é um número válido.");

Com entrada válida, exibe o dobro; com entrada inválida como "abc", cai no else e exibe a mensagem amigável, sem quebrar. O TryParse tornou o programa robusto.

Exercício 3

Explique, com suas palavras, a diferença de comportamento entre int.Parse e int.TryParse quando recebem um texto que não é um número válido. Para dados digitados por um usuário, qual dos dois é o mais apropriado, e por quê?

Ver resposta

✓ Resposta: Diante de um texto que não é número, int.Parse quebra o programa — interrompe a execução com um erro. int.TryParse não quebra: ele apenas devolve falso para indicar que a conversão não deu certo, deixando o programa decidir o que fazer (por exemplo, avisar o usuário). Para dados digitados por um usuário, o mais apropriado é o TryParse, porque a entrada humana é imprevisível e o programa deve reagir a erros com elegância, em vez de quebrar diante de uma digitação inesperada.

Exercício 4

Escreva um programa que peça ao usuário dois números (lidos e convertidos com segurança via TryParse) e exiba a soma deles. Se qualquer uma das entradas for inválida, avise o usuário. (Dica: você precisará converter cada entrada e verificar se ambas deram certo.)

Ver resposta

✓ Resposta: Exemplo:

Console.Write("Primeiro número: ");
bool ok1 = int.TryParse(Console.ReadLine(), out int a);
Console.Write("Segundo número: ");
bool ok2 = int.TryParse(Console.ReadLine(), out int b);

if (ok1 && ok2)
    Console.WriteLine("A soma é: " + (a + b));
else
    Console.WriteLine("Uma das entradas não era um número válido.");

Cada entrada é convertida com segurança, guardando em ok1 e ok2 se deu certo; a soma só é exibida se ambas as conversões tiverem sucesso, e qualquer entrada inválida leva à mensagem de erro. (O && significa "e"; será estudado nas estruturas de decisão, mas aqui indica "se ambas deram certo".)

Exercício 5

Sem escrever código: explique por que o texto "30" e o número 30 são coisas diferentes para o computador, e por que, para calcular com um valor digitado pelo usuário, a conversão é indispensável. Relacione com o "mistério" da aula anterior.

Ver resposta

✓ Resposta: O texto "30" e o número 30 são diferentes para o computador porque têm naturezas distintas: "30" é uma sequência de caracteres (os símbolos '3' e '0'), tratada como texto, com a qual não se faz aritmética; 30 é um valor numérico, com o qual se pode calcular. Para calcular com algo que o usuário digitou, a conversão é indispensável porque tudo o que vem do teclado chega como texto (o "mistério" da aula anterior: ReadLine sempre devolve string), e o texto precisa ser transformado num número de verdade antes que somas, multiplicações ou comparações façam sentido. A conversão é a ponte que liga o que foi digitado (texto) ao que queremos manipular (número).

Comentários

Mais em Linguagem C#

O Coletor de Lixo: A Memória se Gerencia Sozinha
O Coletor de Lixo: A Memória se Gerencia Sozinha

Por que em C# não é preciso liberar memória à mão: o coletor de lixo…

Métodos de Objeto e a Palavra this
Métodos de Objeto e a Palavra this

Como dar comportamento aos objetos: métodos que operam sobre o estado do…

IEnumerable: O que Torna Algo "Percorrível"
IEnumerable: O que Torna Algo "Percorrível"

Por que arrays, listas, dicionários e conjuntos aceitam todos o mesmo foreach…