Подтвердить что ты не робот

Прерывать всякий раз, когда вводится файл (или класс)

В Visual Studio существует ли способ отлаживать отладчик всякий раз, когда вводится определенный файл (или класс)? Пожалуйста, не отвечайте "просто установите точку останова в начале каждого метода":)

Я использую С#.

4b9b3361

Ответ 1

Макросы могут быть вашим другом. Вот макрос, который добавит точку останова для каждого метода в текущем классе (поместите курсор где-нибудь в классе перед запуском).

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

Изменить: Обновлено, чтобы добавить точку останова по имени функции, а не номер файла/строки. Он "чувствует" себя лучше и будет легче распознать в окне точек останова.

Ответ 2

Вы можете начать с введения какого-то Аспектно-ориентированного программирования - см., например, это объяснение - и затем установите точку останова в одном методе OnEnter.

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

Ответ 3

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

Чтобы это вообще работало, точка останова должна быть установлена ​​в начале каждого метода. Независимо от того, выполняете ли вы это вручную или отладчик делает это автоматически, эти точки останова должны быть установлены для этого.

Итак, на самом деле возникает вопрос: "Если в этом есть достаточная потребность в этой функции, стоит ли встраивать в отладчик автоматическое средство установки всех этих контрольных точек?". И ответ: "Не правда".

Ответ 4

Возможно, вы могли бы использовать структуру 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.

Ответ 5

Это отлично работает в WinDbg:

bm exename!CSomeClass::*

(Чтобы уточнить, приведенная выше строка устанавливает точку останова для всех функций в классе, точно так же, как запросит OP, не прибегая к взлому CRT или малым глупостям)

Ответ 6

Эта функция реализована в VS для родного С++. crtl-B и указать "function" как "Classname:: *", это устанавливает точку останова в начале каждого метода класса. Набор точек останова сгруппированы в окне точек останова (ctrl-alt-B), чтобы они могли быть включены, отключены и удалены как группа.

К сожалению, макрос, скорее всего, лучший вариант для управляемого кода.

Ответ 7

Вы можете написать макрос Visual Studio, который получил список всех методов класса (например, прочитав файл .map, созданный рядом с исполняемым файлом, и выполнив поиск его для правильных имен символов (а затем разметки этих имен)), а затем Breakpoints.add(), чтобы программно добавить точки останова для этих функций.

Ответ 8

System.Diagnostics.Debugger.Break();

(в начале каждого метода)

Ответ 9

Нет. Вернее, да, но это связано с установкой точки останова в начале каждого метода.

Ответ 10

Используйте Debugger.Break(); (из пространства имен System.Diagnostics)

Поместите его вверху каждой функции, которую вы хотите "сломать"

void MyFunction()
{
    Debugger.Break();
    Console.WriteLine("More stuff...");
}

Ответ 11

Не самый простой способ приблизиться к этому, чтобы просто установить точку останова в конструкторе (если у вас есть только один или каждый из них в случае нескольких конструкторов)?

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

Это, конечно, не позволяет вам установить точку останова в каждом методе внутри класса.

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

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

Ответ 12

Предполагая, что вас интересуют только публичные методы, т.е. когда методы класса называются "извне", я снова подключу 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).

Конечно, это дополнительный код, но

  • Это полезный код в любом случае, и структура является шаблоном, если вы используете Design by Contract.
  • Иногда вам нужны точки прерывания для исследования некорректного поведения, например, недопустимое состояние объекта, в этом случае инварианты могут быть бесценными.

Для объекта, который всегда действителен, функция Invariant() имеет только тело, которое возвращает true. Вы все равно можете поставить точку останова.

Это просто идея, она, по общему признанию, имеет шаг, поэтому просто рассмотрите ее и используйте, если вам это нравится.

Ответ 13

Чтобы удалить контрольные точки, установленные принятым ответом, добавьте еще один макрос со следующим кодом

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

Ответ 14

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

Ответ 15

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

Ответ 16

Вы можете наложить на нее точку прерывания памяти и настроить ее на чтение. Я думаю, что в большинстве случаев вы будете читать функцию-член. Я не уверен в статических функциях.

Ответ 17

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

при вводе функции он перейдет в отладчик

Ответ 18

ЕСЛИ это С++, о котором вы говорите, тогда вам, возможно, удастся с ним (чертовски много работы) установить точку прерывания в коде преамбулы в CRT или написать код, который изменяет код преамбулы на stick INT 3 там только для функций, сгенерированных из рассматриваемого класса... Это, BTW, МОЖЕТ быть сделано во время выполнения... Вам нужно, чтобы файл PE, который сгенерировал, модифицировал сам, возможно, перед перемещением, чтобы придерживаться всех перерыв там...

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

__asm { int 3 }

в вашем макросе, чтобы сделать перерыв VS... Это не позволит вам установить точки останова в начале каждой функции, но вам все равно придется придерживаться макровызов, что намного лучше, если вы Спроси меня. Я думаю, что я где-то читал о том, как вы можете определить или переопределить код преамбулы, который вызывается для каждой функции. Я посмотрю, что я могу найти.

Я бы подумал, что подобный хак может быть использован для определения того, какой ФАЙЛ вы вводите, но вы ВСЕ ЕЩЕ НЕОБХОДИМО разместить ВАШЕЙ функциональный макрос по всему вашему коду, или он никогда не будет вызван, и, ну, это в значительной степени то, что вы сделали Не хочу делать.

Ответ 19

Если вы хотите использовать макрос, то принятый ответ этот вопрос

Должно быть тривиально конвертируемо для вас, заставляя функцию поиска искать методы, свойства и конструкторы (по желанию), есть также вполне возможно получить одну и ту же информацию от идеалов/символов, которые будут более стабильными (хотя, возможно, немного сложнее).

Ответ 20

Вы можете использовать Debugger.Launch() и Debugger.Break() в сборке System.Diagnostics

Ответ 21

Сумасшедший метод с использованием отражения. Подробнее см. Документацию для 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 (через командную строку, если хотите), чтобы установить точки останова для всех методов и конструкторов данного класса.

Ответ 22

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

Сделать то же самое с типом (который существует во время выполнения) может быть выполнен, но, вероятно, будет очень навязчивым, создавая больше возможностей для heisenbugs. "Самый простой" путь к этому, скорее всего, будет использовать инфраструктуру прокси-сервера .NET remoting (см. Реализацию MOQ на примере использования прозрачного прокси-сервера).

Сводка: используйте макрос или выберите все, за которым следует заданная точка останова (ctrl-A, F9).

Ответ 23

Джоэл, ответ кажется "нет". Нет способа без точки останова при каждом методе.