Exercício – Depurar com o Visual Studio Code
É 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.
No Visual Studio Code, selecione Ficheiro>Abrir Pasta.
Crie uma nova pasta chamada
DotNetDebuggingnuma localização à sua escolha. Em seguida, escolha Selecionar pasta.Abra o terminal integrado do Visual Studio Code selecionando View>Terminal no menu principal.
Na janela de terminal, copie e cole o seguinte comando:
dotnet new consoleEste 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.
Na janela de terminal, copie e cole o seguinte comando para executar o programa "Hello World".
dotnet runA janela do terminal exibe "Hello World!" como saída.
Configurar o Visual Studio Code para a depuração do .NET
Abra Program.cs selecionando-o.
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.
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 .
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...
Abra Program.cs selecionando-o.
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.
Salve o arquivo selecionando Ctrl+S para Windows e Linux. Selecione Cmd+S para Mac.
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
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
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 .
Deverá ver o programa a terminar rapidamente. É normal, uma vez ainda que não adicionou pontos de interrupção.
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
Adicione um ponto de interrupção clicando na margem esquerda na linha 1 em
int result = Fibonacci(5);.
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().
Verificar o estado das variáveis
Agora, reserve algum tempo para inspecionar os valores das diferentes variáveis usando o 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,n2esum?
Em seguida, avançaremos para o
forloop usando o controle do depurador Step Over .
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:
- O ciclo conta de 2 a
n(o número da sequência Fibonacci de que estamos à procura). - Se
nfor inferior a 2, o ciclo nunca será executado. A instruçãoreturnno final da função devolverá 0 senfor 0 e 1 senfor 1 ou 2. Por definição, estes são os valores zero, primeiro e segundo na sequência Fibonacci. - 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,n1en2são os dois valores anteriores esumé o valor da iteração atual. Por isso, sempre que descobrimos a soma dos dois valores anteriores e a definimos comosum, atualizamos os valoresn1en2.
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.
Adicione um segundo ponto de interrupção na linha 13.
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.
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]: 2Todas essas linhas parecem corretas. Na primeira vez que o ciclo é executado, a
sumdos 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.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]: 3Vamos 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.Ok, vamos selecionar Continuar para fazer um loop novamente.
n [int]: 5 n1 [int]: 1 n2 [int]: 2 sum [int]: 3 i [int]: 4Mais uma vez, parece estar tudo correto. Esperamos que o quarto valor da série seja 3.
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
iseja 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?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.
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.
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.
Inicie o depurador uma última vez.
n [int]: 5 n1 [int]: 2 n2 [int]: 3 sum [int]: 3Bem, este resultado não está certo. Pedimos especificamente Fibonacci(5) e obtivemos Fibonacci(4). Esta função devolve
n2e cada iteração do ciclo calcula o valorsume definen2como igual asum.Com base nestas informações e na nossa execução de depuração anterior, podemos ver que o ciclo foi encerrado quando
iera 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 queié igual an. 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; }Se ainda não o fez, pare a sessão de depuração.
Em seguida, faça a alteração anterior para a linha 10 e deixe nosso ponto de interrupção na linha 17.
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]: 5Excelente! Parece que conseguimos. Ótimo trabalho, você salvou o dia para Fibonacci, Inc.!
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.