Olá, José. Como vai?
Uau, que código fantástico! A sua resolução do conversor de temperatura está em um nível de maturidade técnica excelente, muito acima do que normalmente vemos em exercícios iniciais de laços de repetição.
Você não se limitou apenas a fazer o cálculo matemático: estruturou o programa dividindo as responsabilidades em funções limpas, utilizou um switch case elegante para o menu e, o mais impressionante, criou métodos robustos de validação de dados (int.TryParse e byte.TryParse). Blindar o sistema contra entradas vazias ou letras é uma excelente prática de desenvolvimento comercial que evita que o programa trave (crash).
Analisando a sua estrutura, separei duas observações técnicas importantes sobre a precisão matemática e os tipos de dados que você utilizou:
1. Divisão Inteira vs. Precisão com Ponto Flutuante
No C#, quando realizamos operações matemáticas utilizando apenas variáveis ou números do tipo int, o compilador executa uma divisão inteira. Isso significa que qualquer valor após a vírgula é simplesmente descartado (truncado), o que pode gerar pequenas imprecisões no cálculo de temperaturas.
Vamos ver um exemplo prático com a sua função ConverterParaCelsius():
Se o usuário digitar 70°F, a fórmula matemática pura resultaria em 21,11°C.
- No seu código atual:
(70 - 32) * 5 / 9 $\rightarrow$ 38 * 5 / 9 $\rightarrow$ 190 / 9. - Como a operação é inteira,
190 / 9 resulta em 21, descartando os 0,11.
Para resolver isso e permitir que o seu conversor exiba temperaturas quebradas (como 21.1°C ou 36.5°C), o ideal é migrar o tipo numérico de int para double ou float. Veja como as funções de conversão e validação ganhariam muito mais precisão técnica:
void ConverterParaFahrenheit()
{
Console.Write("Digite a temperatura em Celsius: ");
double celsius = ValidacaoNumerica(); // Alterado para double
// Usando 9.0 e 5.0 forçamos o cálculo com ponto flutuante
double fahrenheit = (celsius * 9.0 / 5.0) + 32;
Console.Clear();
// O ":F1" formata o texto para exibir apenas 1 casa decimal
Console.Write($"{celsius:F1}°C equivalem a {fahrenheit:F1}°F");
Thread.Sleep(5000);
}
Para dar suporte a isso, basta alterar o retorno do seu método de validação de int para double:
double ValidacaoNumerica()
{
while (true)
{
string entrada = Console.ReadLine()!;
if (!string.IsNullOrWhiteSpace(entrada))
{
// Alterado para double.TryParse
if (double.TryParse(entrada, out double valida))
{
return valida;
}
}
Console.Write("Valor inválido, tente novamente: ");
}
}
2. Tratamento de Exceções no Fluxo do Switch
Na sua função SelecaoDeOpcoes(), você colocou um default: throw new ArgumentException();.
Embora levantar uma exceção seja o procedimento correto para tratar caminhos inesperados no código, no cenário do seu programa ela nunca será disparada. Isso acontece porque a sua função ValidarOpcaoInformada() já funciona como um filtro intransponível, garantindo que a string retornada seja estritamente "1", "2" ou "3".
Como o valor já chega perfeitamente limpo no switch, você poderia substituir o throw por um simples break; no default, mantendo o código um pouco mais leve, sabendo que a sua validação prévia já está fazendo o trabalho pesado de segurança.
Parabéns pela dedicação, pela organização visual do menu e pelo excelente domínio das funções utilitárias do C#! O seu código está com uma estrutura profissional muito bonita de se ver.
Espero que possa ter lhe ajudado!