Поделиться через


Отладка для абсолютных начинающих

Как правило, код, который мы пишем в качестве разработчиков программного обеспечения, не всегда делает то, что мы ожидаем. Иногда это делает что-то совершенно другое! Когда происходит непредвиденное, следующая задача заключается в том, чтобы выяснить, почему, и хотя мы можем испытать соблазн просто всматриваться в наш код в течение нескольких часов, проще и эффективнее использовать средство отладки или отладчик.

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

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

Уточняйте проблему, задав себе правильные вопросы

Это помогает уточнить проблему, с которыми вы столкнулись, прежде чем попытаться устранить ее. Мы ожидаем, что вы уже столкнулись с проблемой в коде, в противном случае вы не попытаетесь выяснить, как отладить его! Поэтому перед началом отладки убедитесь, что вы определили проблему, которую вы пытаетесь решить:

  • Что вы ожидали, что ваш код будет делать?

  • Что произошло вместо этого?

    Если при запуске приложения возникает ошибка (исключение), это может быть хорошо! Исключение — это непредвиденное событие, возникаемое при выполнении кода, как правило, ошибка какого-либо типа. Средство отладки способно перенести вас точно в место в коде, где произошло исключение, и помочь вам исследовать возможные исправления.

    Если произошло что-то еще, в чем проявляется симптом проблемы? Вы уже подозреваете, где возникла эта проблема в коде? Например, если в коде отображается какой-то текст, но текст неверный, вы знаете, что данные плохи или код, задающий отображаемый текст, имеет какой-то ошибку. Пошагово выполняя код в отладчике, вы можете изучать каждое изменение ваших переменных, чтобы точно узнать, когда и каким образом назначаются неправильные значения.

Изучение ваших предположений

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

  • Вы используете правильный API (то есть правильный объект, функция, метод или свойство)? Api, который вы используете, может не делать то, что вы думаете, что это делает. После проверки вызова API в отладчике исправление может потребовать обращения к документации, чтобы определить правильный API.

  • Правильно ли вы используете API? Может быть, вы использовали правильный API, но не использовали его правильно.

  • Содержит ли код какие-либо опечатки? Некоторые опечатки, такие как простая орфографическая ошибка в имени переменной, могут быть трудно заметны, особенно при работе с языками, которые не требуют объявления переменных перед их использованием.

  • Вы изменили код и предположили, что это не связано с проблемой, которую вы видите?

  • Вы ожидали, что объект или переменная содержат определенное значение (или определенный тип значения), отличное от того, что действительно произошло?

  • Знаете ли вы намерение кода? Часто сложнее отлаживать код другого пользователя. Если это не ваш код, возможно, вам может потребоваться потратить время на обучение именно того, что делает код, прежде чем вы сможете эффективно отладить его.

    Совет

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

Подспрошив предположения, вы можете сократить время, необходимое для поиска проблемы в коде. Вы также можете сократить время, необходимое для устранения проблемы.

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

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

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

В Visual Studio вы войдете в режим отладки с помощью F5 (или команды меню Отладка>Начать отладку или кнопки Начать отладкузначок 'Начать отладку'. на панели инструментов Отладка). Если возникают исключения, Помощник по исключениям Visual Studio переносит вас в точное место, где произошло исключение, и предоставляет другую полезную информацию. Дополнительные сведения об обработке исключений в коде см. в методах отладки и средствах.

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

В Visual Studio можно быстро задать точку останова, щелкнув в левом поле рядом с строкой кода. Или поместите курсор в строку и нажмите клавишу F9.

Чтобы проиллюстрировать эти понятия, мы рассмотрим пример кода, который уже содержит несколько ошибок. Мы используем C#, но функции отладки применяются к Visual Basic, C++, JavaScript, Python и другим поддерживаемым языкам. Пример кода для Visual Basic также предоставляется, но снимки экрана находятся на C#.

Создание примера приложения (с некоторыми ошибками)

Затем вы создадите приложение с несколькими ошибками.

  1. Для этого необходимо установить Visual Studio, а также рабочую нагрузку .NET для разработки настольных приложений .

    Если вы еще не установили Visual Studio, перейдите на страницу загрузки Visual Studio, чтобы установить ее бесплатно.

    Если необходимо установить рабочую нагрузку, но у вас уже есть Visual Studio, выберите Tools>Get Tools and Features. Установщик Visual Studio запускается. Выберите компонент разработки настольных приложений .NET, а затем выберите Изменить.

  2. Откройте Visual Studio.

    В окне запуска выберите Создать проект. Введите консоль в поле поиска, выберите C# или Visual Basic в качестве языка, а затем выберите консольное приложение для .NET. Выберите Далее. Введите ConsoleApp_FirstApp в качестве имени проекта и выберите Далее.

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

    Выберите рекомендуемую целевую платформу или .NET 8, а затем выберите Создать.

    Если вы не видите шаблон проекта консольного приложения для .NET, перейдите в раздел ToolsGet Tools and Features, который открывает Установщик Visual Studio. Выберите рабочую нагрузку разработки .NET, а затем выберите Изменить.

    Visual Studio создает консольный проект, который отображается в обозревателе решений в правой области.

  3. В Program.cs (или Program.vb) замените весь код по умолчанию следующим кодом. (Сначала выберите правильную вкладку языка C# или Visual Basic.)

    using System;
    using System.Collections.Generic;
    
    namespace ConsoleApp_FirstApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Welcome to Galaxy News!");
                IterateThroughList();
                Console.ReadKey();
            }
    
            private static void IterateThroughList()
            {
                var theGalaxies = new List<Galaxy>
            {
                new Galaxy() { Name="Tadpole", MegaLightYears=400, GalaxyType=new GType('S')},
                new Galaxy() { Name="Pinwheel", MegaLightYears=25, GalaxyType=new GType('S')},
                new Galaxy() { Name="Cartwheel", MegaLightYears=500, GalaxyType=new GType('L')},
                new Galaxy() { Name="Small Magellanic Cloud", MegaLightYears=.2, GalaxyType=new GType('I')},
                new Galaxy() { Name="Andromeda", MegaLightYears=3, GalaxyType=new GType('S')},
                new Galaxy() { Name="Maffei 1", MegaLightYears=11, GalaxyType=new GType('E')}
            };
    
                foreach (Galaxy theGalaxy in theGalaxies)
                {
                    Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
                }
    
                // Expected Output:
                //  Tadpole  400,  Spiral
                //  Pinwheel  25,  Spiral
                //  Cartwheel, 500,  Lenticular
                //  Small Magellanic Cloud .2,  Irregular
                //  Andromeda  3,  Spiral
                //  Maffei 1,  11,  Elliptical
            }
        }
    
        public class Galaxy
        {
            public string Name { get; set; }
    
            public double MegaLightYears { get; set; }
            public object GalaxyType { get; set; }
    
        }
    
        public class GType
        {
            public GType(char type)
            {
                switch(type)
                {
                    case 'S':
                        MyGType = Type.Spiral;
                        break;
                    case 'E':
                        MyGType = Type.Elliptical;
                        break;
                    case 'l':
                        MyGType = Type.Irregular;
                        break;
                    case 'L':
                        MyGType = Type.Lenticular;
                        break;
                    default:
                        break;
                }
            }
            public object MyGType { get; set; }
            private enum Type { Spiral, Elliptical, Irregular, Lenticular}
        }
    }
    

    Наше намерение для этого кода заключается в отображении названия галактики, расстояния до галактики и типа галактики все в списке. Для отладки важно понять намерение кода. Ниже приведен формат одной строки из списка, который мы хотим отобразить в выходных данных:

    название галактики, расстояние, тип галактики.

Запуск приложения

Нажмите F5 или кнопку Начать отладку значок , показывающий кнопку на панели инструментов отладки, расположенной над редактором кода.

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

Tadpole  400,  Spiral
Pinwheel  25,  Spiral
Cartwheel, 500,  Lenticular
Small Magellanic Cloud .2,  Irregular
Andromeda  3,  Spiral
Maffei 1,  Elliptical

Но вместо этого вы увидите следующие выходные данные:

Tadpole  400,  ConsoleApp_FirstApp.GType
Pinwheel  25,  ConsoleApp_FirstApp.GType
Cartwheel, 500,  ConsoleApp_FirstApp.GType
Small Magellanic Cloud .2,  ConsoleApp_FirstApp.GType
Andromeda  3,  ConsoleApp_FirstApp.GType
Maffei 1, 11,  ConsoleApp_FirstApp.GType

Глядя на выходные данные и наш код, мы знаем, что GType является именем класса, который хранит тип галактики. Мы пытаемся показать фактический тип галактики (например, "Спираль"), а не имя класса!

Отладка приложения

  1. При запущенном приложении вставьте точку останова.

    В цикле foreach щелкните правой кнопкой мыши рядом с методом Console.WriteLine, чтобы получить контекстное меню, и выберите во всплывающем меню пункт точка останова>Вставить точку останова.

    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears + ",  " + theGalaxy.GalaxyType);
    }
    

    При установке точки останова красная точка отображается в левом поле.

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

  2. Выберите значок перезапускас кнопкой "Перезапустить Приложение" на панели инструментов отладки. кнопка на панели инструментов отладки (CTRLSHIFTF5).

    Приложение приостанавливается в заданной точке останова. Желтое выделение указывает, где отладчик приостановлен (желтая строка кода еще не выполнена).

  3. Наведите указатель мыши на переменную GalaxyType справа, а затем слева от значка с ключом разверните theGalaxy.GalaxyType. Вы видите, что GalaxyType содержит свойство MyGType, и значение этого свойства установлено в Spiral.

    снимок экрана отладчика Visual Studio со строкой кода, выделенной желтым цветом, и меню, открытым под свойством Galaxy GalaxyType.

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

  4. В том же коде, во время отладки, поместите курсор в конец строки с theGalaxy.GalaxyType и измените его на theGalaxy.GalaxyType.MyGType. Хотя вы можете внести изменения, редактор кода отображает ошибку (красная строка с волнистой линией). (В Visual Basic ошибка не отображается, и этот раздел кода работает.)

  5. Нажмите F11 (отладка>вход в или кнопку вход на панели отладки), чтобы выполнить текущую строку кода.

    F11 перемещает отладчик вперед и пошагово выполняет код. F10 (Шаг через) — это аналогичная команда, и обе команды полезны при обучении использованию отладчика.

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

    снимок экрана отладчика Visual Studio со строкой кода, выделенной красным цветом, и поле сообщения с выбранным параметром

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

    снимок экрана отладчика Visual Studio со строкой кода, выделенной красным цветом, и поле сообщения с выбранным параметром

    Заметка

    Для отладки примера кода Visual Basic пропустите следующие несколько шагов, пока не будет указано, как щелкнуть значок перезапуска, на котором отображается кнопка "Перезапустить приложение" на панели инструментов отладки. кнопка.

  6. Выберите Изменить в поле сообщения Горячей перезагрузки или Изменить И Продолжить. Теперь вы видите сообщение об ошибке в окне списка ошибок. Ошибка указывает, что 'object' не содержит определения для MyGType.

    снимок экрана отладчика Visual Studio со строкой кода, выделенной красным цветом, и окно списка ошибок с двумя ошибками, перечисленными.

    Несмотря на то что мы устанавливаем каждую галактику с объектом типа GType (который имеет свойство MyGType), отладчик не распознает объект theGalaxy как объект типа GType. Что происходит? Вы хотите просмотреть любой код, задающий тип галактики. При этом вы видите, что класс GType определенно имеет свойство MyGType, но что-то не так. Сообщение об ошибке о object оказывается подсказкой; для интерпретатора языка тип, как представляется, является объектом типа object вместо объекта типа GType.

  7. Просматривая код, связанный с настройкой типа галактики, вы найдете свойство GalaxyType класса Galaxy указано как object вместо GType.

    public object GalaxyType { get; set; }
    
  8. Измените предыдущий код следующим образом:

    public GType GalaxyType { get; set; }
    
  9. Выберите значок перезапуска, показывающий кнопку на панели инструментов отладки (CTRL + SHIFT + F5) для повторной компиляции кода и перезапуска.

    Теперь, когда отладчик приостанавливается на Console.WriteLine, вы можете навести указатель мыши на theGalaxy.GalaxyType.MyGTypeи убедиться, что значение задано правильно.

  10. Удалите точку останова, щелкнув круг точки останова в левом поле (или щелкните правой кнопкой мыши и выберите точку останова >Удалить точку останова), а затем нажмите клавишу F5, чтобы продолжить.

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

    Tadpole  400,  Spiral
    Pinwheel  25,  Spiral
    Cartwheel, 500,  Lenticular
    Small Magellanic Cloud .2,
    Andromeda  3,  Spiral
    Maffei 1,  Elliptical
    
  11. Установите точку останова в этой строке кода перед оператором switch (перед инструкцией Select в Visual Basic).

    public GType(char type)
    

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

  12. Выберите значок "Перезапуск", показывающий кнопку на той же панели (Ctrl + Shift + F5) для перезапуска.

    Отладчик приостанавливается в строке кода, в которой устанавливается точка останова.

  13. Наведите указатель мыши на переменную type. Отображается значение S (после символьного кода). Вы заинтересованы в значении I, потому что знаете, что это нерегулярный тип галактики.

  14. Нажмите F5 и снова наведите указатель мыши на переменную type. Повторите этот шаг, пока не увидите значение I в переменной type.

    снимок экрана отладчика Visual Studio со строкой кода желтым цветом и окном со значением переменной типа 73 I.

  15. Теперь нажмите клавишу F11 (отладка>шаг в).

  16. Нажимайте F11, пока не остановитесь в строке кода в операторе switch для значения "I" (операторSelect для Visual Basic). Здесь вы увидите четкую проблему, связанную с опечаткой. Вы ожидали, что код перейдет к месту, где он указывает MyGType как нерегулярный тип галактики, но отладчик вместо этого полностью пропускает этот код и приостанавливается на разделе default оператора switch (операторElse в Visual Basic).

    снимок экрана с ошибкой опечатки.

    Глядя на код, вы видите опечатку в инструкции case 'l'. Он должен быть case 'I'.

  17. Выберите код для case 'l' и замените его case 'I'.

  18. Удалите точку останова и нажмите кнопку перезапуска , чтобы перезапустить приложение.

    Исправлены ошибки, и вы увидите ожидаемые выходные данные!

    Нажмите любую клавишу, чтобы завершить работу приложения.

Сводка

При возникновении проблемы используйте отладчик и команды шага , такие как F10 и F11, чтобы найти регион кода с проблемой.

Заметка

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

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

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

  • Проверьте, выполняет ли приложение код, который вы ожидаете. (Например, в образце приложения мы ожидали, что код для оператора switch установит тип галактики как нерегулярный, но приложение пропустило код из-за опечатки.)

Совет

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

Дальнейшие действия

В этой статье вы узнали несколько общих концепций отладки. Затем вы можете узнать больше об отладчике.