В Visual Studio существует ли способ отлаживать отладчик всякий раз, когда вводится определенный файл (или класс)? Пожалуйста, не отвечайте "просто установите точку останова в начале каждого метода":)
Я использую С#.
В Visual Studio существует ли способ отлаживать отладчик всякий раз, когда вводится определенный файл (или класс)? Пожалуйста, не отвечайте "просто установите точку останова в начале каждого метода":)
Я использую С#.
Макросы могут быть вашим другом. Вот макрос, который добавит точку останова для каждого метода в текущем классе (поместите курсор где-нибудь в классе перед запуском).
Public Module ClassBreak
Public Sub BreakOnAnyMember()
Dim debugger As EnvDTE.Debugger = DTE.Debugger
Dim sel As EnvDTE.TextSelection = DTE.ActiveDocument.Selection
Dim editPoint As EnvDTE.EditPoint = sel.ActivePoint.CreateEditPoint()
Dim classElem As EnvDTE.CodeElement = editPoint.CodeElement(vsCMElement.vsCMElementClass)
If Not classElem Is Nothing Then
For Each member As EnvDTE.CodeElement In classElem.Children
If member.Kind = vsCMElement.vsCMElementFunction Then
debugger.Breakpoints.Add(member.FullName)
End If
Next
End If
End Sub
End Module
Изменить: Обновлено, чтобы добавить точку останова по имени функции, а не номер файла/строки. Он "чувствует" себя лучше и будет легче распознать в окне точек останова.
Вы можете начать с введения какого-то Аспектно-ориентированного программирования - см., например, это объяснение - и затем установите точку останова в одном методе OnEnter.
В зависимости от того, какую структуру AOP вы выберете, это потребует небольшого количества украшений в вашем коде и немного накладных расходов (которые вы можете удалить позже), но по крайней мере вам не нужно будет устанавливать точки останова повсюду. В некоторых рамках вы можете даже представить его без изменения кода вообще, просто XML файл сбоку?
Ну, как говорят все, он включает установку точки останова в начале каждого метода. Но вы не видите большую картину.
Чтобы это вообще работало, точка останова должна быть установлена в начале каждого метода. Независимо от того, выполняете ли вы это вручную или отладчик делает это автоматически, эти точки останова должны быть установлены для этого.
Итак, на самом деле возникает вопрос: "Если в этом есть достаточная потребность в этой функции, стоит ли встраивать в отладчик автоматическое средство установки всех этих контрольных точек?". И ответ: "Не правда".
Возможно, вы могли бы использовать структуру AOP, такую как PostSharp, чтобы входить в отладчик всякий раз, когда вводится метод. Посмотрите на очень короткое руководство по эту страницу для примера, как вы можете регистрировать/трассировать всякий раз, когда вводится метод.
Вместо ведения журнала в вашем случае вы можете поместить инструкцию Debugger.Break() в обработчик OnEntry. Хотя отладчик не останавливался в ваших методах, но в обработчике OnEntry (поэтому я не уверен, действительно ли это помогает).
Здесь очень простой пример:
Аспектный класс определяет обработчик OnEntry, который вызывает Debugger.Break():
[Serializable]
public sealed class DebugBreakAttribute : PostSharp.Laos.OnMethodBoundaryAspect
{
public DebugBreakAttribute() {}
public DebugBreakAttribute(string category) {}
public string Category { get { return "DebugBreak"; } }
public override void OnEntry(PostSharp.Laos.MethodExecutionEventArgs eventArgs)
{
base.OnEntry(eventArgs);
// debugger will break here. Press F10 to continue to the "real" method
System.Diagnostics.Debugger.Break();
}
}
Затем я могу применить этот аспект к моему классу, где я хочу, чтобы отладчик прерывался всякий раз, когда вызывается метод:
[DebugBreak("DebugBreak")]
public class MyClass
{
public MyClass()
{
// ...
}
public void Test()
{
// ...
}
}
Теперь, если я создам и запускаю приложение, отладчик остановится в обработчике OnEntry(), когда вызывается один из методов MyClass. Все, что я должен сделать, это нажать F10, и я использую метод MyClass.
Это отлично работает в WinDbg:
bm exename!CSomeClass::*
(Чтобы уточнить, приведенная выше строка устанавливает точку останова для всех функций в классе, точно так же, как запросит OP, не прибегая к взлому CRT или малым глупостям)
Эта функция реализована в VS для родного С++. crtl-B и указать "function" как "Classname:: *", это устанавливает точку останова в начале каждого метода класса. Набор точек останова сгруппированы в окне точек останова (ctrl-alt-B), чтобы они могли быть включены, отключены и удалены как группа.
К сожалению, макрос, скорее всего, лучший вариант для управляемого кода.
Вы можете написать макрос Visual Studio, который получил список всех методов класса (например, прочитав файл .map
, созданный рядом с исполняемым файлом, и выполнив поиск его для правильных имен символов (а затем разметки этих имен)), а затем Breakpoints.add()
, чтобы программно добавить точки останова для этих функций.
System.Diagnostics.Debugger.Break();
(в начале каждого метода)
Нет. Вернее, да, но это связано с установкой точки останова в начале каждого метода.
Используйте Debugger.Break(); (из пространства имен System.Diagnostics)
Поместите его вверху каждой функции, которую вы хотите "сломать"
void MyFunction()
{
Debugger.Break();
Console.WriteLine("More stuff...");
}
Не самый простой способ приблизиться к этому, чтобы просто установить точку останова в конструкторе (если у вас есть только один или каждый из них в случае нескольких конструкторов)?
Это приведет к отладке при первом создании экземпляра в случае нестатического конструктора, а в случае статического конструктора/класса вы будете входить в отладку, как только Visual Studio решит инициализировать ваш класс.
Это, конечно, не позволяет вам установить точку останова в каждом методе внутри класса.
Конечно, вы не будете продолжать входить в отладку при последующем повторном входе в код класса (при условии, что вы используете тот же экземплярный объект в следующий раз), однако, если вы повторно создаете экземпляр нового объекта каждый раз изнутри вызывающего кода вы можете имитировать это.
Однако в обычных терминах нет простого способа установить единую точку разрыва в одном месте (например) и заставить ее вступать в отладку каждый раз, когда вводится код класса (из любого метода) (насколько я знаю).
Предполагая, что вас интересуют только публичные методы, т.е. когда методы класса называются "извне", я снова подключу Design by Contract.
Вы можете привыкнуть писать свои публичные функции следующим образом:
public int Whatever(int blah, bool duh)
{
// INVARIANT (i)
// PRECONDITION CHECK (ii)
// BODY (iii)
// POSTCONDITION CHECK (iv)
// INVARIANT (v)
}
Затем вы можете использовать функцию Invariant(), которую вы будете вызывать (i) и установить в ней точку останова. Затем проверьте стек вызовов, чтобы узнать, откуда вы. Конечно, вы также назовете это (v); если вам действительно интересны только точки входа, вы можете использовать вспомогательную функцию для вызова Invariant из (i) и другого из (v).
Конечно, это дополнительный код, но
Для объекта, который всегда действителен, функция Invariant() имеет только тело, которое возвращает true. Вы все равно можете поставить точку останова.
Это просто идея, она, по общему признанию, имеет шаг, поэтому просто рассмотрите ее и используйте, если вам это нравится.
Чтобы удалить контрольные точки, установленные принятым ответом, добавьте еще один макрос со следующим кодом
Public Sub RemoveBreakOnAnyMember()
Dim debugger As EnvDTE.Debugger = DTE.Debugger
Dim bps As Breakpoints
bps = debugger.Breakpoints
If (bps.Count > 0) Then
Dim bp As Breakpoint
For Each bp In bps
Dim split As String() = bp.File.Split(New [Char]() {"\"c})
If (split.Length > 0) Then
Dim strName = split(split.Length - 1)
If (strName.Equals(DTE.ActiveDocument.Name)) Then
bp.Delete()
End If
End If
Next
End If
End Sub
Не то, чтобы я знал. Лучшее, что вы можете сделать, это поставить точку останова в каждом методе в файле или классе. Что ты пытаешься сделать? Вы пытаетесь выяснить, какой метод вызывает что-то изменить? Если это так, возможно, будет более подходящей точка останова данных.
Вы можете написать метод обертки, через который вы производите вызов в своем приложении. Затем вы устанавливаете точку останова в этом единственном методе. Но... ты был бы сумасшедшим, чтобы что-то делать.
Вы можете наложить на нее точку прерывания памяти и настроить ее на чтение. Я думаю, что в большинстве случаев вы будете читать функцию-член. Я не уверен в статических функциях.
you can use the following macro:
#ifdef _DEBUG
#define DEBUG_METHOD(x) x DebugBreak();
#else
#define DEBUG_METHOD(x) x
#endif
#include <windows.h>
DEBUG_METHOD(int func(int arg) {)
return 0;
}
при вводе функции он перейдет в отладчик
ЕСЛИ это С++, о котором вы говорите, тогда вам, возможно, удастся с ним (чертовски много работы) установить точку прерывания в коде преамбулы в CRT или написать код, который изменяет код преамбулы на stick INT 3 там только для функций, сгенерированных из рассматриваемого класса... Это, BTW, МОЖЕТ быть сделано во время выполнения... Вам нужно, чтобы файл PE, который сгенерировал, модифицировал сам, возможно, перед перемещением, чтобы придерживаться всех перерыв там...
Мое единственное другое предложение - написать макрос, который использует предопределенный макрос __FUNCTION__, в котором вы ищете любую функцию, являющуюся частью рассматриваемого класса, и при необходимости придерживайтесь
__asm { int 3 }
в вашем макросе, чтобы сделать перерыв VS... Это не позволит вам установить точки останова в начале каждой функции, но вам все равно придется придерживаться макровызов, что намного лучше, если вы Спроси меня. Я думаю, что я где-то читал о том, как вы можете определить или переопределить код преамбулы, который вызывается для каждой функции. Я посмотрю, что я могу найти.
Я бы подумал, что подобный хак может быть использован для определения того, какой ФАЙЛ вы вводите, но вы ВСЕ ЕЩЕ НЕОБХОДИМО разместить ВАШЕЙ функциональный макрос по всему вашему коду, или он никогда не будет вызван, и, ну, это в значительной степени то, что вы сделали Не хочу делать.
Если вы хотите использовать макрос, то принятый ответ этот вопрос
Должно быть тривиально конвертируемо для вас, заставляя функцию поиска искать методы, свойства и конструкторы (по желанию), есть также вполне возможно получить одну и ту же информацию от идеалов/символов, которые будут более стабильными (хотя, возможно, немного сложнее).
Вы можете использовать Debugger.Launch()
и Debugger.Break()
в сборке System.Diagnostics
Сумасшедший метод с использованием отражения. Подробнее см. Документацию для MethodRental.SwapMethodBody
. В псевдокоде:
void SetBreakpointsForAllMethodsAndConstructorsInClass (string classname)
{
find type information for class classname
for each constructor and method
get MSIL bytes
prepend call to System.Diagnostics.Debugger.Break to MSIL bytes
fix up MSIL code (I'm not familiar with the MSIL spec. Generally, absolute jump targets need fixing up)
call SwapMethodBody with new MSIL
}
Затем вы можете передать имя класса в качестве аргумента runtime (через командную строку, если хотите), чтобы установить точки останова для всех методов и конструкторов данного класса.
Файлы не существуют во время выполнения (считайте, что частичные классы ничем не отличаются - с точки зрения кода - от помещения всего в один файл). Поэтому требуется макро-подход (или код в каждом методе).
Сделать то же самое с типом (который существует во время выполнения) может быть выполнен, но, вероятно, будет очень навязчивым, создавая больше возможностей для heisenbugs. "Самый простой" путь к этому, скорее всего, будет использовать инфраструктуру прокси-сервера .NET remoting (см. Реализацию MOQ на примере использования прозрачного прокси-сервера).
Сводка: используйте макрос или выберите все, за которым следует заданная точка останова (ctrl-A, F9).
Джоэл, ответ кажется "нет". Нет способа без точки останова при каждом методе.