Упражнение. Отладка с помощью Visual Studio Code

Завершено

Пришло время поставить недавно приобретенные знания по отладке на практике. Предположим, вы только что приступили к работе и вам нужно применить свои навыки отладки в .NET для исправления ошибки в важнейшем продукте компании — калькуляторе Фибоначчи.

Создание примера проекта .NET для отладки

Чтобы настроить Visual Studio Code для отладки в .NET, вам прежде всего нужен проект .NET. Visual Studio Code содержит встроенный терминал, который упрощает создание проектов.

  1. В Visual Studio Code выберите Файл>Открыть папку.

  2. Создайте в произвольном месте новую папку с именем DotNetDebugging. Затем выберите "Выбрать папку".

  3. Откройте интегрированный терминал в Visual Studio Code, выбрав Вид>Терминал из главного меню.

  4. Скопируйте и вставьте следующую команду в окно терминала:

    dotnet new console
    

    Эта команда создает файл Program.cs в папке с базовой программой Hello World, уже написанной. Он также создает файл проекта C# с именем DotNetDebugging.csproj.

  5. Чтобы запустить программу Hello World, скопируйте и вставьте следующую команду в окно терминала.

    dotnet run
    

    В окне терминала отображается "Hello, world!" в качестве выходных данных.

Настройка Visual Studio Code для отладки в .NET

  1. Откройте Program.cs , выбрав его.

  2. Когда вы впервые открываете файл C# в Visual Studio Code, появляется запрос на установку рекомендуемых расширений для C#. Если вы видите этот запрос, нажмите кнопку "Установить " в запросе.

    Снимок экрана: запрос Visual Studio Code на установку расширения C#.

  3. Visual Studio Code установит расширение C# и отобразит еще один запрос на добавление необходимых ресурсов для сборки и отладки проекта. Нажмите кнопку "Да ".

    Снимок экрана: запрос Visual Studio Code для добавления необходимых ресурсов для сборки и отладки проекта .NET.

  4. Вы можете закрыть вкладку Extension: C# , чтобы сосредоточиться на коде, который мы отладим.

Добавление программной логики в калькулятор Фибоначчи

Пока наш проект просто выдает в консоль сообщение Hello World, и отлаживать здесь нечего. Вместо этого вы будете использовать короткую программу .NET для вычисления N-го числа последовательности Fibonacci.

Последовательность Фибоначчи — это ряд чисел, который начинается с 0 и 1, где каждое следующее число является суммой двух предыдущих. Последовательность выглядит следующим образом:

0, 1, 1, 2, 3, 5, 8, 13, 21...
  1. Откройте Program.cs , выбрав его.

  2. Замените содержимое Program.cs следующим кодом:

    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;
    }
    

    Примечание.

    Этот код содержит ошибку, и в этом модуле показано, как ее устранить. Мы не рекомендуем использовать этот код в реальных приложениях для вычисления последовательности Фибоначчи, пока эта ошибка не будет исправлена.

  3. Сохраните файл, нажав клавиши CTRL+S для Windows и Linux. Выберите cmd+S для Mac.

  4. Давайте рассмотрим, как работает обновленный код перед отладкой. Запустите программу, введя в окне терминала следующую команду:

    dotnet run
    

    Окно терминала с измененными выходными данными программы.

  5. Результат, 3, показан в выходных данных терминала. При просмотре этой диаграммы последовательности Фибоначчи, показывающей положение последовательности на основе нуля для каждого значения в круглых скобках, вы увидите, что результат должен быть равен 5. А значит, самое время узнать с тем, как отладчик поможет нам исправить программу.

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

Анализ проблем

  1. Запустите программу, выбрав вкладку "Запуск и отладка " слева, а затем нажмите кнопку "Начать отладку ". Сначала может потребоваться выбрать кнопку "Запуск и отладка ", а затем выбрать файл Program.cs .

    Снимок экрана: кнопка

    Программа выполнится быстро. Это нормально, так как вы еще не добавили точки останова.

  2. Если консоль отладки не отображается, выберите CTRL+SHIFT+Y для Windows и Linux или CMD+SHIFT+Y для Mac. Вы увидите несколько строк с диагностическими сведениями и следующие строки в самом конце:

    ...
    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).
    

Строки в верхней части этого фрагмента информируют о том, что в параметрах отладки по умолчанию включен параметр "Только мой код". Это означает, что отладчик будет отлаживать только ваш код программы, не переходя к исходному коду .NET, пока включен этот режим. Это позволяет не отвлекаться от отладки собственного кода.

В завершающей части выходных данных на консоли отладки видно, что программа выводит в консоль результат "3" и завершает выполнение с кодом 0. Обычно код завершения 0 означает, что запущенная программа завершила работу без сбоев. Но отсутствие сбоя не означает, что программа возвращает правильное значение. В нашем примере программа должна вычислить значение пятого элемента последовательности Фибоначчи:

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

В реальной последовательности пятый элемент имеет значение 5, но наша программа вернула значение 3. Давайте воспользуемся отладчиком для диагностики и устранения этой проблемы.

Использование точек останова и пошаговое выполнение

  1. Добавьте точку останова, щелкнув в левом поле на строке 1.int result = Fibonacci(5);

    Снимок экрана: место расположения точки останова в коде.

  2. Снова начните отладку. Программа начнет выполнение. Оно прервется (приостановится) на строке 1, так как вы установили точку останова. С помощью элементов управления перейдите в функцию Fibonacci().

    Скриншот кнопки «Шаг внутрь».

Проверка состояния переменных

Теперь потребуется некоторое время для проверки значений различных переменных с помощью панели "Переменные ".

Снимок экрана: панель

  • Какое значение отображается для параметра n?
  • Какие значения имеют локальные переменные n1, n2 и sum в начале выполнения функции?
  1. Затем мы перейдем к циклу for с помощью команды отладчика Step Over.

    Снимок экрана: кнопка

  2. Продолжайте выполнять эти шаги, пока не дойдете до первой строки в цикле for, которая выглядит так:

    sum = n1 + n2;
    

Примечание.

Возможно, вы заметили, что для перемещения по строке for(...) {} требуется несколько команд выполнения шага с заходом. Эта ситуация возникает из-за нескольких операторов в этой строке. При пошаговом выполнении вы переходите к следующему оператору в коде. Обычно существует один оператор на строку. Но если это не так, вам нужно выполнить несколько шагов, чтобы перейти к следующей строке.

Подумайте о коде

Важная часть отладки — остановиться и на основании имеющейся информации предположить, что пытаются делать части кода (и функции, и блоки, например циклы). Ничего страшного, если вы не уверены, это часть процесса отладки. Но активное участие в процессе отладки поможет вам гораздо быстрее обнаруживать ошибки.

Прежде чем продолжать работу, давайте вспомним теорию. Последовательность Фибоначчи — это ряд чисел, который начинается с 0 и 1, где каждое следующее число является суммой двух предыдущих.

Это означает, что:

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)

Зная это определение, мы можем сделать следующие выводы при анализе цикла for:

  1. Цикл ведет отсчет от 2 до n (нужное число в последовательности Фибоначчи).
  2. Если значение n меньше 2, цикл не выполняется. Оператор return в конце функции вернет значение 0, если n равно 0, или 1, если n равно 1 или 2. Это по определению нулевое, первое и второе значения последовательности Фибоначчи.
  3. Самое интересное начинается, когда значение n больше 2. В этом случае текущее значение определяется как сумма двух предыдущих значений. В нашем цикле n1 и n2 обозначают два предыдущих значения, а sum — вычисляемое значение в текущей итерации. При этом каждый раз вычисляется сумма двух предыдущих значений, результат сохраняется в sum, а затем обновляются значения n1 и n2.

Этой информации будет достаточно. Мы можем положиться на наш отладчик. Тем не менее размышлять о коде полезно, чтобы понять, выполняется ли он ожидаемым образом, и быть готовым к ситуации, когда это не так.

Обнаружение ошибки с помощью точек останова

Пошаговое выполнение кода может оказаться полезным, но емким, особенно при работе с циклами или другим кодом, который вызывается многократно. Чтобы не проходить цикл снова и снова, мы можем установить новую точку останова в первой строке цикла.

На этом этапе важно правильно выбрать стратегию размещения точек останова. Мы особенно заинтересованы в значении sum, так как он представляет текущее максимальное значение Fibonacci. Давайте из-за этого поместим точку останова в строку послеsum того, как она будет установлена.

  1. Добавьте еще одну точку останова в строке 13.

    Снимок экрана, показывающий, что устанавливается вторая точка останова.

    Примечание.

    Если вы заметили, что продолжаете выполнять свой код, а затем переходите на одну или две строки, вы можете переместить точки останова на более релевантные строки.

  2. Теперь, когда у нас есть хорошая точка останова в цикле, используйте управление отладчиком Продолжить, чтобы продолжать до тех пор, пока точка останова не будет достигнута. Проверяя локальные переменные, мы видим следующие строки:

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

    Все эти строки кажутся правильными. При первом прохождении цикла сумма (sum) двух предыдущих значений равна 1. И вместо того, чтобы проходить цикл построчно, мы можем воспользоваться нашими точками останова, чтобы перейти к следующему циклу.

  3. Нажмите кнопку "Продолжить , чтобы продолжить поток программы" до тех пор, пока не будет достигнута следующая точка останова, которая будет находиться на следующем проходе через цикл.

    Примечание.

    Не беспокойтесь о пропуске ошибки при использовании "Продолжить". Вы будете часто выполнять отладку кода несколько раз, чтобы найти ошибку. Обычно быстрее будет несколько раз выполнить такую отладку, чем проявлять чрезмерную осторожность и выполнять код пошагово.

    На этот раз мы видим следующее:

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

    Давайте поразмыслим. Имеют ли смысл эти значения? Пока все выглядит нормально. Мы ожидаем, что третье число в последовательности Фибоначчи равно 2, и переменная sum имеет именно это значение.

  4. Хорошо, давайте снова нажмите кнопку "Продолжить ".

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

    И снова все выглядит неплохо. Четвертый элемент нашей последовательности должен быть равен 3.

  5. Возможно, вы уже сомневаетесь в том, что в коде была ошибка, ведь все работает правильно! Давайте не торопиться с выводами и пройдем последнюю итерацию цикла. Нажмите кнопку "Продолжить еще раз".

    Но что это? Программа завершила работу и вернула значение 3! Это неправильно.

    Но не беспокойтесь. Это не провал, а всего лишь новый урок. Теперь мы знаем, что код правильно повторяет цикл до тех пор, пока не значение i не будет равно 4, после чего выполнение завершается без вычисления итогового значения. Я начинаю получать некоторые идеи о том, где ошибка. А Вы?

  6. Давайте установим еще одну точку останова на строке 17 со следующим кодом:

    return n == 0 ? n1 : n2;
    

    Эта точка останова позволит нам проверить состояние программы перед выходом из функции. Мы уже проверили все, что можно проверить на предыдущих точках останова (строки 1 и 13), и теперь их можно удалить.

  7. Удалите предыдущие точки останова в строках 1 и 13. Это можно сделать, щелкнув их в поле рядом с номерами строк, или сняв флажки для точек останова для строк 1 и 13 в области точек останова в левом нижнем углу.

    Снимок экрана: точки останова, перечисленные в области точек останова.

    Теперь мы намного лучше понимаем, что происходит. А установив точку останова, предназначенную для того, чтобы отследить момент неправильного выполнения программы, мы сможем перехватить ошибку!

  8. Запустите отладчик в последний раз.

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

    Вот и наша ошибка. Мы запрашивали значение Fibonaccci(5), а получили Fibonacci(4). Эта функция возвращает n2, а каждая итерация цикла вычисляет значение sum и задает для n2 значение sum.

    На основе этих сведений и результатов предыдущего сеанса отладки можно понять, что цикл завершил работу, когда значение i было равно 4, а не 5.

    Давайте подробнее рассмотрим первую строку цикла for.

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

    Но что это? Это означает, что он завершит работу, как только верхняя часть цикла for увидит, что значение i больше не меньше n. Это означает, что код цикла не будет выполняться, если i равно n. Вместо этого нам нужно было, чтобы цикл выполнялся до i <= n.

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

    После исправления программа будет выглядеть так:

    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. Закройте сеанс отладки, если вы еще это не сделали.

  10. Затем сделайте предыдущее изменение на строку 10 и оставьте точку останова в строке 17.

  11. Перезапустите отладчик. Теперь при достижении точки останова на строке 17 мы увидим следующие значения:

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

    Эй! Кажется, мы все починили! Отличная работа, вы спасли ситуацию для Фибоначчи, Инк.!

  12. Нажмите кнопку "Продолжить" , чтобы убедиться, что программа возвращает правильное значение.

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

    Выходные данные правильные.

Вы справились! Вы отладили фрагмент чужого кода, используя отладчик .NET в Visual Studio Code.

В следующем уроке показано, как сделать свой код более пригодным к отладке с помощью функций ведения журнала и трассировки, встроенных в .NET.