Значение отладчика в работе программиста трудно переоценить. Как бы вы хорошо не писали код, как бы не была хороша ваша команда, но даже если ваш проект имеет всего несколько тысяч строк кода, написанных двумя разработчиками, то вы не можете гарантировать отсутствие ошибок. Да, современные IDE, в частности, Visual Studio, позволяют избегать множества ошибок уже на этапе написания кода, но, как минимум, вы можете упустить какие-то моменты, из-за которых ваше приложение работает не так быстро, как хотелось бы, или ошибка возникает при каких-то граничных условиях, которые не были рассмотрены ранее. Разобраться в причинах не корректной работы помогает отладчик.
Отладчик Visual Studio, на мой взгляд, самый удобный и мощный среди всех IDE написанный на текущий момент. Даже если мы рассматриваем не только среду .NET.
Конечно, существуют более специализированные вещи, представляющие из себя гораздо более мощные инструменты. Можете обратить внимание на диаграмму:
Изображение взято из статьи отсюда: https://habrahabr.ru/company/jugru/blog/326454/ (в статье вы можете узнать больше про WinDbg)
Но отладчик Visual Studio достаточно универсальный, он может помочь, наверное, с поиском 98% возникающих проблем в проектах. Но проблема в том, что очень много разработчиков не использует все возможности отладчика. Даже когда мы говорим об опытных программистах, которые работают много лет и успешно пишут код, не используют множество доступного функционала, который может здорово упростить жизнь и сэкономить время. Многие скажут, что это и не нужно, код можно писать и в блокноте, а во время отладки достаточно узнать какое значение приходит, получить код ошибки и, возможно, увидеть несколько шагов обработки. И я с ними соглашусь – конечно можно, если у вас не ограниченный запас времени и средств. Во всех остальных случаем нужно, как минимум, знать возможности инструмента, которым пользуешься каждый день.
Точка останова(breakpoint)
Самый простой способ использование отладчика, это поставить точку останова, получить прерывание программы, узнать какие есть значения и по шагам посмотреть, как идёт обработка переменных. Но давайте рассмотрим вот такой пример, упрощённый, для понимания ситуации:
for (int i = 10; i >= -10; i--)
{
var result = 100 / i;
Console.WriteLine(result);
}
Сразу понятно, что здесь будет проблема из-за деления на ноль. Но, ведь это упрощенный пример. И, допустим, что вы знаете что ваша программа "падает", когда i принимает 0. Но, чтобы попасть в такую ситуацию, многие используют НЕВЕРНЫЕ подходы, например:
- Поставить точку останова жать F5 и следить за изменением i.
- Дополнить код следующим образом:
for (int i = 10; i >= -10; i--)
{
if (i == 0)
{
var breakpoint = true;
}
var result = 100 / i;
Console.WriteLine(result);
}
И поставить точку останова в операторе if, или более удобный вариант с использованием Debugger.Break();
НЕ делайте так! Ведь для этого есть куда более удобный и действенный способ. Поставьте точку останова, затем наведите на неё мышкой и выберете Settings, затем Conditions и в Conditional Expression запишите i == 0
После внесения изменений можно нажать на Close, чтобы меню Settings не занимало место. А ваша точка останова будет прерывать работу программы только когда i станет равно нулю. Можно писать сложные выражения, используя несколько параметров, а не один, как в показанному примере.
Также выбрать нужные параметры, вы можете, нажав на точку останова правой клавишей мыши:
Здесь же становятся доступны необходимые действия и видны горячие клавиши для их вызова.
Помимо "Conditional Expression", есть еще такой параметр как "Hit Count". Данный параметр срабатывает, когда точка останова была "задета" (строка, на которой установлена данная точка останова была вызвана) какое-то количества раз равное, кратное или больше либо равно указанному.
Это позволяет вам прерываться, например, когда значения четные или при каждом сотом вызове.
Conditional Filter позволяет настраивать прерывание когда вы работаете с потоками, процессами или код выполняется на машине с определённым именем.
Actions
Если вы хотите получать какую-то информацию из кода, при этом не меняя его, вы можете воспользоваться возможностями Actions. Немаловажным является наличии параметра "Continue execution", который позволяет не делать прерывания программы на точке останова.
Выводить можно следующую информацию:
- В фигурных скобках можно выводить значения переменных, функций. То есть вы можете выводить не только значения самих переменных, но и значения, уже обработанные какими-то функциями.
- $ADDRESS — текущая инструкция. Например "ShowDebugs.Program.Main(string[]) + 0x00000047"
- $CALLER — функция, из которой была вызвана текущая. Если цикле примера я вызову функцию, то в ней выведет "ShowDebugs.Program.Main"
- $CALLSTACK — стек вызовов
- $FUNCTION — имя текущей функции. Например, "ShowDebugs.Program.Main(string[])"
- $PID — идентификатор процесса. Например, "0x3870"
- $PNAME — название процесса. Например, "C:\Users\FlashPC\source\repos\ShowDebugs\ShowDebugs\bin\Debug\ShowDebugs.exe"
- $TID — идентификатор потока. Например, "0x3E58"
- $TNAME — название потока. Например, "Main Thread"
Стоит обратить внимание на то, что изменять параметры отображаемой информации вы можете прямо во время выполнения программы.
В процессе работы с отладчиком, может получиться ситуации, когда вы поставили излишнее количество точек останова, которые начинают мешать. Для удобной работы с множеством точек останова можно вызвать окно "Breakpoints" (Debug – Windows - Breakpoints)
В нем можно увидеть все установленные точки останова. Удалить не нужные или настроить существующие:
В Labels вы можете записывать данные, позволяющие вам быстро идентифицировать нужную точку останова, если есть необходимость сохранять активными большое их количество.
"Set next statement to here" и "immediate window"
"Set next statement to here" полезна тем, что вы можете вернуться в коде к более раннему состоянию.
Используя "immediate window" вы можете как получать сведения о различных элементах кода, так и задавать состояния различным переменным. Рассмотрим работу одного из ранее созданных чат-ботов.
Запустив чат-бот и выполнив команду help, я попадаю в выставленную точку останова. Зайдя в "immediate window" пишу "user" и нажимаю enter.
В удобном виде я могу увидеть значения всех используемых параметров.
Теперь я вернусь в строку получения пользователя. Для этого нужно навести курсор на требуемую строчку, нажать на Ctrl и когда появится желтая стрелка нажать на её.
После этого текущая строка для обработки поменяется на указанную а я, например, смогу изменить локаль пользователя. Записав в "immediate window" строку «user.Locale = "en-US"»
Значение будет изменено. Двигаясь дальше по строчкам кода можно будет заметить, что код отработает уже для изменённой локали. И всё это делается очень быстро, без необходимости перезапускать проект.
Также стоит заметить, что в окне "immediate window" поддерживается использования IntelliSense. Нажмите Ctrl+Space и вы увидите все доступные переменные и функции, которые вы можете использовать.
Заострю внимание, что в "Immediate Window" можно запрашивать вывод значений для сложных вещей. Например, можно запросить вызов получения данных из базы данных, одним из используемых вами методом:
Используйте LINQ для получения более детальной информации. Он так же поддерживается.
Diagnostic Tools
Говорить про отладку и не рассказать про "Diagnostic Tools" было бы большим упущением. Запущу тот же чат-бот, отправлю команду и посмотрю, что мне приходит.
Доступна информация по использованию оперативной памяти, загрузке процессора, количество обработанных событий, количество исключений.
Взглянув в Exception, можно отреагировать на произошедшие исключения.
Список событий, которые выводятся в общий список можно настраивать, отображая только то, за чем необходимо следить в данный момент:
Если вы используете, например, Entity Framework, то здесь вы можете увидеть код сгенерированных и отправленных SQL запросов. Что позволяет их легко отслеживать и оптимизировать.
Щелкнув два раза по такому событию, вы можете увидеть место, из которого оно было вызвано:
Также вы можете получить весь сгенерированный SQL запрос.
Если у вас есть проблемы с производительностью, подобная информация, порой очень сильно упрощает поиск узких мест.
Используя "Diagnostic tools" вы так же можете исследовать использование оперативной памяти вашим приложением и нагрузку на CPU.
Конечно вы можете использовать такие вещи как, например, dotMemory и dotTrace. Но подавляющее большинство проблем можно обнаружить и средствами Visual Studio.
DebuggerDisplay
Для более удобного отображения выводимой информации можно использовать возможности атрибута DebuggerDisplay. О нём я уже писал в далёком 2015. Повторяться я не буду. Кто не в курсе что это такое, рекомендую ознакомиться http://flash2048.com/post/DebuggerDisplay
Отладка — это то, с чем действительно приходится сталкиваться всем разработчикам. Знание данного инструмента обязательно. Отладчик Visual Studio очень мощный и удобный, используя его можно находить проблемы практически любой сложности. А знание описанного функционала может здорово сэкономить вам время и нервы.
Если я забыл указать какие-то дополнительные инструменты Visual Studio, которые удобно использовать для для повышение качества отладки, свяжитесь со мной, с удовольствием добавлю информацию о них.
А вообще — всем кода без ошибок.
Приятного программирования.