Exercício – Depurar com o Visual Studio Code

Concluído

É hora de colocar em prática seus conhecimentos de depuração recém-adquiridos. É o seu primeiro dia de trabalho e tem de colocar em prática as suas competências de depuração do .NET ao corrigir um erro no produto principal da empresa, uma calculadora Fibonacci.

Criar um projeto .NET de exemplo para depuração

Para configurar o Visual Studio Code para a depuração do .NET, primeiro precisamos de um projeto .NET. O Visual Studio Code inclui um terminal integrado, o que facilita a criação de um novo projeto.

  1. No Visual Studio Code, selecione Ficheiro>Abrir Pasta.

  2. Crie uma nova pasta chamada DotNetDebugging numa localização à sua escolha. Em seguida, escolha Selecionar pasta.

  3. Abra o terminal integrado do Visual Studio Code selecionando View>Terminal no menu principal.

  4. Na janela de terminal, copie e cole o seguinte comando:

    dotnet new console
    

    Este comando cria um arquivo Program.cs em sua pasta com um programa básico "Hello World" já escrito. Ele também cria um arquivo de projeto C# chamado DotNetDebugging.csproj.

  5. Na janela de terminal, copie e cole o seguinte comando para executar o programa "Hello World".

    dotnet run
    

    A janela do terminal exibe "Hello World!" como saída.

Configurar o Visual Studio Code para a depuração do .NET

  1. Abra Program.cs selecionando-o.

  2. Depois de abrir um ficheiro C# no Visual Studio Code pela primeira vez, receberá um pedido para instalar as extensões recomendadas para C#. Se você vir esse prompt, selecione o botão Instalar no prompt.

    Captura de tela do prompt do Visual Studio Code para instalar a extensão C#.

  3. O Visual Studio Code instalará a extensão C# e mostrará outro prompt para adicionar os ativos necessários para compilar e depurar o seu projeto. Selecione o botão Sim .

    Captura de ecrã do prompt do Visual Studio Code para adicionar os ativos necessários para compilar e depurar o seu projeto .NET.

  4. Você pode fechar a guia Extensão: C# para se concentrar no código que iremos depurar.

Adicionar a lógica do programa Fibonacci

O nosso projeto atual escreve uma mensagem “Hello World” na consola, o que não nos dá muito para depurar. Em vez disso, você usará um programa .NET curto para calcular o número Nda sequência de Fibonacci.

A sequência Fibonacci é um conjunto de números a começar com o número 0 e 1, sendo que todos os outros números seguintes são a soma dos dois anteriores. A sequência prossegue desta forma:

0, 1, 1, 2, 3, 5, 8, 13, 21...
  1. Abra Program.cs selecionando-o.

  2. Substitua o conteúdo do Program.cs pelo seguinte código:

    int result = Fibonacci(5);
    Console.WriteLine(result);
    
    static int Fibonacci(int n)
    {
        int n1 = 0;
        int n2 = 1;
        int sum;
    
        for (int i = 2; i < n; i++)
        {
            sum = n1 + n2;
            n1 = n2;
            n2 = sum;
        }
    
        return n == 0 ? n1 : n2;
    }
    

    Nota

    Este código contém um erro, que vamos depurar posteriormente neste módulo. Não recomendamos que o utilize em aplicações Fibonacci críticas até corrigirmos o erro.

  3. Salve o arquivo selecionando Ctrl+S para Windows e Linux. Selecione Cmd+S para Mac.

  4. Vamos dar uma olhada em como o código atualizado funciona antes de depurá-lo. Execute o programa ao introduzir o seguinte comando no terminal:

    dotnet run
    

    Janela terminal com saída de programa modificada.

  5. O resultado, 3, é mostrado na saída do terminal. Ao consultar este gráfico de sequência de Fibonacci que mostra a posição da sequência baseada em zero para cada valor entre parênteses, verá que o resultado deveria ter sido 5. Está na altura de se familiarizar com o depurador e corrigir este programa.

    0 (0), 1 (1), 1 (2), 2 (3), 3 (4), 5 (5), 8 (6), 13 (7), 21 (8)...
    

Analisar os problemas

  1. Inicie o programa selecionando a guia Executar e Depurar à esquerda e, em seguida, selecionando o botão Iniciar depuração . Talvez seja necessário selecionar primeiro o botão Executar e Depurar e, em seguida, selecionar o arquivo Program.cs .

    Captura de tela do botão Iniciar depuração no Visual Studio Code.

    Deverá ver o programa a terminar rapidamente. É normal, uma vez ainda que não adicionou pontos de interrupção.

  2. Se o console de depuração não aparecer, selecione Ctrl+Shift+Y para Windows e Linux ou Cmd+Shift+Y para Mac. Deverá ver várias linhas de informações de diagnóstico, seguidas destas linhas no final:

    ...
    Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.0\System.Threading.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
    Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.0\System.Text.Encoding.Extensions.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
    3
    The program '[88820] DotNetDebugging.dll' has exited with code 0 (0x0).
    

As linhas na parte superior indicam que as predefinições de depuração ativam a opção "Just My Code". Isso significa que o depurador só depurará seu código e não entrará no código-fonte do .NET, a menos que você desabilite esse modo. Esta opção permite concentrar-se na depuração do código.

No final da saída da consola de depuração, verá que o programa escreve 3 na consola e, em seguida, encerra com o código 0. Normalmente, um código de saída do programa 0 indica que o mesmo foi executado e encerrado sem falhas. No entanto, há uma diferença entre falhar e devolver o valor correto. Neste caso, pedimos ao programa que calculasse o quinto valor da sequência Fibonacci:

0 (0), 1 (1), 1 (2), 2 (3), 3 (4), 5 (5), 8 (6), 13 (7), 21 (8)...

O quinto valor nesta lista é 5, mas o nosso programa devolveu 3. Vamos utilizar o depurador para diagnosticar e corrigir este erro.

Utilizar pontos de interrupção e a execução passo a passo

  1. Adicione um ponto de interrupção clicando na margem esquerda na linha 1 em int result = Fibonacci(5);.

    Captura de tela do local do ponto de interrupção no código.

  2. Comece a depurar novamente. O programa começa a ser executado. Ele quebra (pausa a execução) na linha 1 devido ao ponto de interrupção definido. Utilize os controlos do depurador para avançar para a função Fibonacci().

    Captura de ecrã do botão Step into.

Verificar o estado das variáveis

Agora, reserve algum tempo para inspecionar os valores das diferentes variáveis usando o painel Variáveis .

Captura de tela do painel Variáveis.

  • Qual é o valor apresentado para o parâmetro n?
  • No início da execução da função, quais são os valores das variáveis locais n1, n2 e sum?
  1. Em seguida, avançaremos para o for loop usando o controle do depurador Step Over .

    Captura de ecrã do botão Avançar.

  2. Continue a avançar até chegar à primeira linha no ciclo for, a qual indica:

    sum = n1 + n2;
    

Nota

Deverá ter reparado que são necessários múltiplos comandos de intervenção para percorrer a linha for(...) {}. Esta situação ocorre porque existem várias declarações nesta linha. Ao intervir, avança para a instrução seguinte no seu código. Normalmente, existe uma instrução por linha. Se esse não for o caso, são necessários múltiplos passos para avançar para a linha seguinte.

Pensar no código

Uma parte importante da depuração consiste em parar e pensar sobre o que acha que as partes do código (funções e blocos, como ciclos) estão a tentar fazer. Não há problema se não tiver a certeza. Tudo isso faz parte do processo de depuração. No entanto, ao envolver-se ativamente no processo de depuração, conseguirá localizar os erros de forma muito mais rápida.

Antes de avançarmos, vale a pena relembrar que a sequência Fibonacci é uma série de números a começar com o número 0 e 1, sendo que todos os outros números seguintes são a soma dos dois anteriores.

Tal significa que:

Fibonacci(0) = 0
Fibonacci(1) = 1
Fibonacci(2) = 1 (0 + 1)
Fibonacci(3) = 2 (1 + 1)
Fibonacci(4) = 3 (1 + 2)
Fibonacci(5) = 5 (2 + 3)

Considerando esta definição e analisando o ciclo for, podemos deduzir que:

  1. O ciclo conta de 2 a n (o número da sequência Fibonacci de que estamos à procura).
  2. Se n for inferior a 2, o ciclo nunca será executado. A instrução return no final da função devolverá 0 se n for 0 e 1 se n for 1 ou 2. Por definição, estes são os valores zero, primeiro e segundo na sequência Fibonacci.
  3. O caso mais interessante ocorre quando n é superior a 2. Nesses casos, o valor atual é definido como a soma dos dois valores anteriores. Portanto, neste ciclo, n1 e n2 são os dois valores anteriores e sum é o valor da iteração atual. Por isso, sempre que descobrimos a soma dos dois valores anteriores e a definimos como sum, atualizamos os valores n1 e n2.

Não temos de pensar em demasia depois disso. Podemos recorrer um pouco ao nosso depurador. Contudo, vale a pena pensarmos no código para ver se este faz o que esperamos e estarmos mais informados quando tal não acontece.

Localizar o erro com pontos de interrupção

Percorrer seu código pode ser útil, mas tedioso, especialmente quando você está trabalhando com loops ou outro código que é chamado repetidamente. Em vez de percorrermos o ciclo repetidamente, podemos definir um novo ponto de interrupção na primeira linha do mesmo.

Quando o fazemos, é importante pensarmos estrategicamente sobre onde colocar os pontos de interrupção. Estamos especialmente interessados no valor do , porque ele representa o valor máximo atual de sumFibonacci. Por causa disso, vamos colocar nosso ponto de interrupção na linha depoissum que for definido.

  1. Adicione um segundo ponto de interrupção na linha 13.

    Captura de tela mostrando um segundo ponto de interrupção sendo definido.

    Nota

    Se constatar que continua a executar o código e a avançar uma linha ou duas, pode facilmente atualizar os pontos de interrupção para linhas mais eficazes.

  2. Agora que temos um bom ponto de interrupção definido no loop, use o controlo Continue do depurador para avançar até que o ponto de interrupção seja atingido. Se observarmos as nossas variáveis locais, vemos as seguintes linhas:

    n [int]: 5
    n1 [int]: 0
    n2 [int]: 1
    sum [int]: 1
    i [int]: 2
    

    Todas essas linhas parecem corretas. Na primeira vez que o ciclo é executado, a sum dos dois valores anteriores é 1. Em vez de percorrermos o código linha a linha, podemos aproveitar os nossos pontos de interrupção para avançarmos para a próxima vez no ciclo.

  3. Selecione Continuar para continuar o fluxo do programa até que o próximo ponto de interrupção seja atingido, que estará na próxima passagem pelo loop.

    Nota

    Não se preocupe muito em ignorar o bug quando usar Continuar. Deve estar ciente de que, por vezes, terá de depurar o código várias vezes para encontrar o problema. Normalmente, é mais rápido percorrê-lo algumas vezes do que ser excessivamente cuidadoso ao examiná-lo.

    Desta vez, vemos os seguintes valores:

    n [int]: 5
    n1 [int]: 1
    n2 [int]: 1
    sum [int]: 2
    i [int]: 3
    

    Vamos pensar nisso. Estes valores ainda fazem sentido? Parece que sim. Para o terceiro número Fibonacci, esperamos ver que a sum é igual a 2, o que efetivamente acontece.

  4. Ok, vamos selecionar Continuar para fazer um loop novamente.

    n [int]: 5
    n1 [int]: 1
    n2 [int]: 2
    sum [int]: 3
    i [int]: 4
    

    Mais uma vez, parece estar tudo correto. Esperamos que o quarto valor da série seja 3.

  5. Nesta fase, é possível que se comece a perguntar se o código afinal estava correto e imaginou o erro! Vamos executar um último ciclo. Selecione Continuar mais uma vez.

    Espere. O programa concluiu a execução e imprimiu 3. Este resultado não está certo.

    OK, não se preocupe. Não falhamos, aprendemos. Agora sabemos que o código passa pelo ciclo corretamente até que i seja igual a 4, mas, em seguida, é encerrado antes de calcular o valor final. Estou começando a ter algumas ideias sobre onde está o bug. Estás?

  6. Vamos definir mais um ponto de interrupção na linha 17, que diz:

    return n == 0 ? n1 : n2;
    

    Este ponto de interrupção permitirá que inspecionemos o estado do programa antes da saída da função. Já aprendemos tudo o que podemos esperar dos nossos breakpoints anteriores nas linhas 1 e 13, para que possamos eliminá-los.

  7. Remova os pontos de interrupção anteriores nas linhas 1 e 13. Você pode fazer isso clicando neles na margem ao lado dos números de linha ou desmarcando as caixas de seleção do ponto de interrupção para as linhas 1 e 13 no painel Pontos de interrupção no canto inferior esquerdo.

    Captura de ecrã a mostrar os pontos de interrupção listados no painel Pontos de interrupção.

    Agora que compreendemos muito melhor o que está a acontecer e definimos um ponto de interrupção concebido para detetar o funcionamento incorreto do programa, deveremos conseguir encontrar o erro.

  8. Inicie o depurador uma última vez.

    n [int]: 5
    n1 [int]: 2
    n2 [int]: 3
    sum [int]: 3
    

    Bem, este resultado não está certo. Pedimos especificamente Fibonacci(5) e obtivemos Fibonacci(4). Esta função devolve n2 e cada iteração do ciclo calcula o valor sum e define n2 como igual a sum.

    Com base nestas informações e na nossa execução de depuração anterior, podemos ver que o ciclo foi encerrado quando i era 4, e não 5.

    Vamos examinar melhor a primeira linha do ciclo for.

    for (int i = 2; i < n; i++)
    

    Espere! Isso significa que ele sairá assim que o topo do loop for ver que não é mais do que in. Tal significa que o código do ciclo não será executado para o caso em que i é igual a n. Em vez disso, queríamos que o código fosse executado até i <= n:

    for (int i = 2; i <= n; i++)
    

    Com essa alteração, o programa atualizado deverá ter o seguinte aspeto:

    int result = Fibonacci(5);
    Console.WriteLine(result);
    
    static int Fibonacci(int n)
    {
        int n1 = 0;
        int n2 = 1;
        int sum;
    
        for (int i = 2; i <= n; i++)
        {
            sum = n1 + n2;
            n1 = n2;
            n2 = sum;
        }
    
        return n == 0 ? n1 : n2;
    }
    
  9. Se ainda não o fez, pare a sessão de depuração.

  10. Em seguida, faça a alteração anterior para a linha 10 e deixe nosso ponto de interrupção na linha 17.

  11. Reinicie o depurador. Desta vez, quando atingirmos o ponto de interrupção na linha 17, veremos os seguintes valores:

    n [int]: 5
    n1 [int]: 3
    n2 [int]: 5
    sum [int]: 5
    

    Excelente! Parece que conseguimos. Ótimo trabalho, você salvou o dia para Fibonacci, Inc.!

  12. Selecione Continuar apenas para certificar-se de que o programa retorna o valor correto.

    5
    The program '[105260] DotNetDebugging.dll' has exited with code 0 (0x0).
    

    Obtemos a saída correta.

Conseguiu! Depurou código que não foi escrito por si com o depurador do .NET no Visual Studio Code.

Na unidade seguinte, aprenderá a tornar o código mais fácil de depurar com as funcionalidades de registo e rastreio incorporadas no .NET.