Parâmetros e Conversão de Dados em C# com VS Code

Objetivo da Aula:

Capacitar os alunos a criar programas C# que interagem com o ambiente, recebendo e processando parâmetros da linha de comando, e a dominar as diversas formas de conversão de dados, incluindo implícita, explícita, System.Convert, e os conceitos de Boxing e Unboxing.

Público-Alvo:

Estudantes de programação com conhecimento básico em C# e uso do VS Code.

Duração Estimada:

1h30min - 2h (dependendo do ritmo dos alunos e da profundidade das discussões/exercícios).

Materiais Necessários:

  • Computadores com Visual Studio Code (VS Code) e SDK do .NET instalados e configurados.

  • Quadro ou lousa para anotações.


Parte 1: Recebimento e Tratamento de Parâmetros (45-60 minutos)

1. Introdução (5 minutos)

  • Professor: "Olá a todos! Hoje vamos aprender como nossos programas C# podem ser mais inteligentes e flexíveis, aceitando informações de fora (parâmetros da linha de comando) e como manipular esses dados (conversões). Isso é super útil para criar ferramentas dinâmicas!"

  • Professor: Perguntar aos alunos: "Alguém já viu programas que vocês executam e podem colocar informações extras depois do nome do programa?" (Ex: git commit -m "minha mensagem"). Explicar que é isso que vamos aprender a fazer.

2. Configurando o Projeto no VS Code (10 minutos - Mão na Massa)

  • Professor: Instruir os alunos a abrir o VS Code.

  • Professor: Abrir o Terminal Integrado (Ctrl+').

  • Professor: Comandos no terminal:

    Bash

    dotnet new console -o ParametroApp
    cd ParametroApp
    code .
  • Professor: "Lembrem-se, o code . vai reabrir o VS Code na pasta do nosso novo projeto. Isso é muito prático!"

3. Entendendo o Main e os Parâmetros (string[] args) (10 minutos)

  • Professor: Abrir Program.cs.

  • Professor: Explicar a assinatura do método Main: static void Main(string[] args).

    • Focar no string[] args. "Este args é um array de strings, e é para cá que o C# joga todas as palavras que digitarmos depois do nome do nosso programa."

    • Explicar que cada item no array é um parâmetro.

  • Professor: Exemplo Prático (Exibir Parâmetros Simples):

    // Program.cs
    namespace ParametroApp
    {
        internal class Program
        {
            static void Main(string[] args)
            {
                if (args.Length > 0)
                {
                    Console.WriteLine("Parâmetros recebidos:");
                    for (int i = 0; i < args.Length; i++)
                    {
                        Console.WriteLine($"Parâmetro {i + 1}: {args[i]}");
                    }
                }
                else
                {
                    Console.WriteLine("Nenhum parâmetro foi fornecido.");
                    Console.WriteLine("Tente executar o programa com parâmetros, por exemplo:");
                    Console.WriteLine("dotnet run -- primeiro segundo terceiro");
                }
            }
        }
    }
  • Professor: Execução e Explicação do --:

    • dotnet run (sem parâmetros)

    • dotnet run -- meu parametro de teste (com parâmetros)

    • Crucial: Explicar o --. "Este -- é um separador. Ele diz ao comando dotnet run: 'O que vem depois de mim não é para você, dotnet run, é para o meu programa C#!' Sem ele, o dotnettentaria interpretar 'meu' como uma opção dele mesmo."

4. Tratando Parâmetros: Um Exemplo Prático de Saudações (15-20 minutos)

  • Professor: "Agora que sabemos como receber, vamos aprender a tratar esses parâmetros. Vamos fazer um programa de saudação personalizada!"

  • Professor: Explicar a ideia de "flags" ou "opções" (como -n para nome, -s para saudação).

  • Professor: Código no Program.cs:

    // Program.cs
    namespace ParametroApp
    {
        internal class Program
        {
            static void Main(string[] args)
            {
                string nome = "Visitante";
                string saudacaoTipo = "Olá";
    
                for (int i = 0; i < args.Length; i++)
                {
                    if (args[i] == "-n" || args[i] == "--nome")
                    {
                        if (i + 1 < args.Length)
                        {
                            nome = args[i + 1];
                            i++; // Avança para pular o valor do nome
                        }
                        else
                        {
                            Console.WriteLine("Erro: O argumento -n ou --nome requer um valor.");
                        }
                    }
                    else if (args[i] == "-s" || args[i] == "--saudacao")
                    {
                        if (i + 1 < args.Length)
                        {
                            saudacaoTipo = args[i + 1];
                            i++; // Avança para pular o valor da saudação
                        }
                        else
                        {
                            Console.WriteLine("Erro: O argumento -s ou --saudacao requer um valor.");
                        }
                    }
                    else
                    {
                        Console.WriteLine($"Aviso: Parâmetro '{args[i]}' não reconhecido.");
                    }
                }
                Console.WriteLine($"{saudacaoTipo}, {nome}!");
            }
        }
    }
  • Professor: Testes com alunos:

    • dotnet run

    • dotnet run -- -n Alice

    • dotnet run -- -s BoaNoite -n Bob

    • dotnet run -- -n Carla -s Olá

    • dotnet run -- -n David parametro_extra

  • Professor: Reforçar: args.Length, for loop para iterar, tratamento de erro (if (i + 1 < args.Length)).


Parte 2: Conversão de Dados (45-60 minutos)

1. Introdução à Conversão (5 minutos)

  • Professor: "Perfeito! Agora que nossos programas podem receber dados, precisamos saber como transformá-los. E se o usuário digitar '10' como texto e precisarmos somar com outro número? Aí entram as conversões de dados."

  • Professor: "Vamos criar um novo projeto para focar só nisso."

2. Configurando o Novo Projeto de Conversão (5 minutos - Mão na Massa)

  • Professor: No terminal, criar um novo projeto:

    Bash

    cd ..
    dotnet new console -o ConversaoDadosApp
    cd ConversaoDadosApp
    code .

3. Conversão Implícita (10 minutos)

  • Professor: "A conversão implícita é a mais 'tranquila'. Ela acontece automaticamente quando o C# tem certeza que não haverá perda de dados. Pensem em colocar um copo de água num balde: a água cabe, e o balde é maior."

  • Professor: Código no Program.cs:

    // Program.cs
    namespace ConversaoDadosApp
    {
        internal class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("--- Conversão Implícita ---");
                int meuInt = 100;
                long meuLong = meuInt; // int para long
                Console.WriteLine($"int para long: {meuInt} -> {meuLong}");
    
                int outroInt = 250;
                float meuFloat = outroInt; // int para float
                Console.WriteLine($"int para float: {outroInt} -> {meuFloat}");
    
                float outroFloat = 123.45f;
                double meuDouble = outroFloat; // float para double
                Console.WriteLine($"float para double: {outroFloat} -> {meuDouble}");
                Console.WriteLine("\n--- Fim da Conversão Implícita ---\n");
            }
        }
    }
  • Professor: Executar: dotnet run

  • Professor: "Notem que o código funciona sem reclamar. O compilador do C# é inteligente e sabe que long pode guardar qualquer int, por exemplo."

4. Conversão Explícita (Casting) (15 minutos)

  • Professor: "Agora, e se for o contrário? Tentar colocar um balde de água num copo? Aí temos um problema! O compilador não vai fazer isso sozinho, porque pode haver perda de dados. Precisamos dizer a ele explicitamente que estamos cientes do risco, usando o casting."

  • Professor: Código no Program.cs:

    // ... (Manter código anterior ou apagar) ...
    Console.WriteLine("--- Conversão Explícita (Casting) ---");
    double valorDouble = 9.99;
    int valorInt = (int)valorDouble; // double para int (truncamento)
    Console.WriteLine($"double para int: {valorDouble} -> {valorInt}");
    
    long numeroLongoGrande = 2147483648L; // Maior que o máximo de int
    int numeroInt2 = (int)numeroLongoGrande; // long para int (estouro de inteiro)
    Console.WriteLine($"long para int (valor maior): {numeroLongoGrande} -> {numeroInt2}");
    Console.WriteLine("Atenção: Houve perda de dados neste caso (estouro de inteiro)!");
    
    char meuChar = 'A';
    int charParaInt = (int)meuChar; // char para int (valor ASCII/Unicode)
    Console.WriteLine($"char para int: '{meuChar}' -> {charParaInt} (valor ASCII/Unicode)");
    Console.WriteLine("\n--- Fim da Conversão Explícita ---\n");
  • Professor: Executar: dotnet run

  • Professor: "Observem a sintaxe (TipoDesejado)variavel. É como se estivéssemos falando: 'Compilador, eu sei o que estou fazendo, pode converter, mesmo que perca dados!' No double para int, a parte decimal é simplesmente cortada. No long para int, se o número for muito grande, ele 'estoura' e vira outro número, que não é o que esperávamos!"

5. Usando System.Convert (15 minutos)

  • Professor: "Quando a gente lida muito com strings (textos) que na verdade representam números, ou precisa de um controle maior sobre as conversões, o System.Convert é nosso melhor amigo. Ele tem métodos específicos para cada tipo e é mais robusto, podendo nos avisar se algo deu errado com exceções."

  • Professor: Código no Program.cs:

    C#

    // ... (Manter código anterior ou apagar) ...
    Console.WriteLine("--- Usando System.Convert ---");
    string textoNumero = "123";
    int numeroConvertido = Convert.ToInt32(textoNumero); // string para int
    Console.WriteLine($"string para int: '{textoNumero}' -> {numeroConvertido}");
    
    int outroNumero = 456;
    string textoOutroNumero = Convert.ToString(outroNumero); // int para string
    Console.WriteLine($"int para string: {outroNumero} -> '{textoOutroNumero}'");
    
    string textoInvalido = "Olá Mundo";
    try
    {
        int numeroInvalido = Convert.ToInt32(textoInvalido);
    }
    catch (FormatException)
    {
        Console.WriteLine($"Erro: Não foi possível converter '{textoInvalido}' para int. Formato inválido.");
    }
    Console.WriteLine("\n--- Fim de System.Convert ---\n");
  • Professor: Executar: dotnet run

  • Professor: "Vejam como ele consegue converter de string para número e de número para string. E o mais importante: se a string não for um número válido, ele nos avisa com uma exceção(FormatException), que podemos 'pegar' com um try-catch para que nosso programa não trave."

6. Boxing e Unboxing (15 minutos)

  • Professor: "Esses são conceitos mais avançados, mas muito importantes para entender como C# lida com diferentes tipos de memória. O C# tem tipos de valor (como int, double, bool) que guardam o valor diretamente, e tipos de referência (como string, object, classes) que guardam um endereço para onde o valor está na memória."

  • Professor: Explicar Boxing: "Quando pegamos um tipo de valor e o tratamos como um object (que é um tipo de referência), o C# precisa 'empacotá-lo'. Isso é o Boxing. Ele cria um novo espaço na memória (no 'heap', para referências) e copia o valor para lá."

  • Professor: Código para Boxing:

    C#

    // ... (Manter código anterior ou apagar) ...
    Console.WriteLine("--- Boxing ---");
    int numeroOriginal = 123;
    object objetoBoxed = numeroOriginal; // Boxing: int para object
    Console.WriteLine($"Número Original (int): {numeroOriginal}");
    Console.WriteLine($"Objeto Boxed (object): {objetoBoxed}");
    Console.WriteLine($"Tipo do objeto Boxed: {objetoBoxed.GetType()}");
    
    double pi = 3.14;
    object piBoxed = pi; // Boxing de um double
    Console.WriteLine($"Valor PI Original (double): {pi}");
    Console.WriteLine($"Objeto PI Boxed (object): {piBoxed}");
    Console.WriteLine($"Tipo do objeto PI Boxed: {piBoxed.GetType()}");
    Console.WriteLine("\n--- Fim do Boxing ---\n");
  • Professor: Executar: dotnet run

  • Professor: Explicar Unboxing: "Agora, se queremos pegar aquele valor que foi 'empacotado' no object e trazê-lo de volta para o seu tipo de valor original, fazemos o Unboxing. Mas cuidado! Para o Unboxing funcionar, você tem que 'desempacotar' para o mesmo tipo que foi empacotado. Se tentar para um tipo diferente, o C# vai reclamar feio!"

  • Professor: Código para Unboxing:

    C#

    // ... (Manter código anterior ou apagar) ...
    Console.WriteLine("--- Unboxing ---");
    object objetoBoxedInt = 456; // Primeiro, fazemos um boxing
    int numeroUnboxed = (int)objetoBoxedInt; // Unboxing: object de volta para int
    Console.WriteLine($"Objeto Boxed (int): {objetoBoxedInt}");
    Console.WriteLine($"Número Unboxed (int): {numeroUnboxed}");
    
    object objetoBoxedIntParaShort = 99; // Boxeado como int
    try
    {
        short numeroUnboxedParaShort = (short)objetoBoxedIntParaShort; // ERRO: Tentar unboxar int para short!
    }
    catch (InvalidCastException ex)
    {
        Console.WriteLine($"Erro no Unboxing para tipo diferente: {ex.Message}");
        Console.WriteLine("Você só pode fazer unboxing para o tipo original (int, neste caso).");
    }
    Console.WriteLine("\n--- Fim do Unboxing ---\n");
  • Professor: Executar: dotnet run

  • Professor: "Prestem atenção ao InvalidCastException. Ele acontece porque, embora short e intsejam números, o Unboxing exige que você volte exatamente para o tipo original que foi boxeado."


Parte 3: Exercício Prático e Discussão (15-20 minutos)

1. Proposta de Exercício (10 minutos)

  • Professor: "Agora é a vez de vocês colocarem a mão na massa e aplicarem tudo o que aprendemos!"

  • Professor: Apresentar o exercício:

    Crie um novo programa de console que:

    1. Declare uma variável decimal com um valor monetário (ex: 150.75m).

    2. Converta esse valor para int usando conversão explícita e mostre o resultado. Peça para eles comentarem a perda de precisão.

    3. Declare uma variável string contendo um número de telefone (ex: "123456789").

    4. Converta essa string para um long usando System.Convert e mostre o resultado.

    5. Tente converter a string "não é um número" para um int usando System.Convert dentro de um bloco try-catch para lidar com a exceção, e exiba uma mensagem de erro amigável se a conversão falhar.

    6. Declare uma variável bool com o valor true.

    7. Faça o boxing dessa variável bool para um object.

    8. Faça o unboxing do object de volta para um bool.

    9. Tente fazer o unboxing do object (que era um bool) para um int dentro de um try-catch e explique a exceção.

2. Discussão e Dúvidas (5-10 minutos)

  • Professor: Abrir para perguntas enquanto os alunos trabalham ou após tentarem resolver o exercício.

  • Professor: Reforçar os cenários de uso para cada tipo de conversão.

    • Implícita: Sempre que for seguro, o C# faz sozinho.

    • Explícita (Casting): Quando o risco de perda de dados é aceitável e você quer forçar a conversão (ex: ignorar decimais).

    • System.Convert: Melhor para conversões de/para strings e para tipos base, com bom controle de erros.

    • Boxing/Unboxing: Para interagir com o tipo object ou coleções que esperam objects (embora genéricos sejam mais recomendados hoje), mas sabendo do impacto no desempenho e da rigidez do unboxing.


Atualizado