Отладка .NET/С#: как отладить классический heisenbug?
Недавно я столкнулся с классическим Heisenbug. Здесь ситуация:
- У меня есть список деревьев, основной вид на одной панели и подробный вид на другой панели справа, который отображает информацию о выбранном дереве node. (Очень похоже на проводник Windows.)
- Когда я добавляю новый node в дерево (подумайте о том, чтобы щелкнуть правой кнопкой мыши папку в проводнике Windows и сказать "Создать → Папка" ), выбранный вновь созданный node будет выбран.
- И вот ошибка: подробный вид справа должен обновиться, чтобы показать новый node. Однако это не так. Мне нужно переключиться на другое дерево node один раз, прежде чем я увижу информацию о новом node в подробном представлении.
Ошибка легко воспроизводится и происходит в конфигурациях сборки "Release" и "Debug". Но: Как только я установил точку останова в обработчике события (для пункта меню "Добавить новый node" ) и включите его, все будет работать отлично = > Heisenbug! Мне не нужно делать настоящую отладку. Нажатие "продолжить" после того, как точка останова попадет, достаточно.
Для лучшего понимания я сделал видео, которое должно иллюстрировать, что происходит.
Все, что я мог придумать, чтобы избавиться от проблемы, заключалось в том, чтобы поток (приложение был однопоточным) спать в течение нескольких секунд, но это не работает.
Я бы очень признателен за любые предложения о том, что я могу попытаться определить причину проблемы. Или, может быть, кто-то догадывается о причине?
Я нацелен на структуру 3.5 и использую x86 в качестве платформы решений. Элемент управления списком деревьев находится в DevExpress ' Элементы управления WinForms; Версия Visual Studio - 2010.
Спасибо
Обновление 3: Проблема решена. Проблема заключалась в том, что вызов метода Focus() детального представления не вызвал события GotFocus, что имеет решающее значение для обновления подробного представления. (Я не знаю, почему, возможно, это уже было в центре внимания.) Однако метод не подвел, он просто ничего не сделал.
Теперь я просто фокусирую другой элемент управления, прежде чем сосредоточиться на подробном представлении и на нем. Причина, по которой все хорошо работало во время отладки, заключалось в том, что переход с Visual Studio обратно в мое приложение правильно задал фокус на подробном представлении.
Основным препятствием для поиска этой проблемы было то, что установка контрольной точки в обработчике событий GotFocus бесполезна: в любое время, когда вы пытаетесь переключиться с Visual Studio на приложение, событие GotFocus получает повторное срабатывание, и вы застряли в бесконечной петле. Комментарии о том, как это можно обойти, приветствуются.
Во всяком случае, моя конкретная проблема решена.
Спасибо всем, кто ответил или прокомментировал. Это очень помогло мне.
Обновление 2: В моем коде я выбираю вновь созданный node в дереве. Это вызывает FocusedNodeChangedEvent. В соответствующем обработчике событий я обновляю подробное представление и вызываю его метод Focus().
Кажется, что это не удается, когда нет точки останова. Я думаю, что правильное обновление во время отладки - это то, что детальное представление автоматически получает фокус.
Сообщения окна
Обновление 1: Ниже приведены оконные сообщения, предоставленные с помощью Eddy. (Длинный список удаленных сообщений)
Ответы
Ответ 1
Впервые я видел видео для поддержки SO:)
Я думаю, что правая панель или контрольная группа нуждаются (-ыми), чтобы иметь Invalidate()
, называемый - который, как мне кажется, срабатывает, потому что он переключается на VS, перегружая окно. Затем, когда вы переключаетесь обратно, он заставляет все перерисовывать, тем самым делая его работу.
Ответ 2
Поместите System.Diagnostics.Debugger.Break() в процедуру обновления для другого окна. Затем, когда появляется ошибка, будет запущена точка прерывания времени выполнения, и вы можете просмотреть стек.
Ответ 3
Когда у вас есть "heisenbug", вам нужно посмотреть, что происходит, но с более легким прикосновением, которое не прерывает поток программы.
Я бы предположил, что вы формируете гипотезу о том, где лежит ваша проблема. Затем я редактировал код для включения вызовов различных методов класса Debug, которые проверяют гипотезу или просто дают информацию о времени выполнения для диагностики, Затем запустите свой код в режиме отладки и посмотрите, что вы получаете на выходе.
Если у вас есть более неуловимый "hiesenbug", тэг происходит только в режиме выпуска, вам нужно будет свернуть свой собственный механизм ведения журнала, чтобы собрать ваши доказательства.
Ответ 4
Кажется, что проблема связана не с тем, чтобы получить правильное событие, вызываемое для запуска и обновления дочерней панели. При попадании на точку останова ваше приложение теряет фокус, и когда вы возвращаете его, он снова получает его (что отличает его от запуска). Чтобы проверить, какие события и не вызваны, а какая разница между двумя сценариями, добавьте следующий код в форму, чтобы увидеть все появившиеся сообщения окна.
protected override void WndProc(ref Message winmsg)
{
base.WndProc(ref winmsg);
System.Diagnostics.Debug.WriteLine(winmsg.Msg + " - " + winmsg);
}
Сравнение различий может помочь вам определить способ решения этой проблемы.