c# - una - la aplicacion se encuentra en modo de interrupcion visual studio 2017
se rompe cada vez que se ingresa un archivo(o clase) (23)
En Visual Studio, ¿hay alguna manera de hacer que el depurador se rompa cada vez que se ingresa un determinado archivo (o clase)? Por favor, no responda "simplemente establezca un punto de interrupción al comienzo de cada método" :)
Estoy usando C #.
Bueno, como todos dicen, se trata de establecer un punto de interrupción al comienzo de cada método. Pero no estás viendo la imagen más grande.
Para que esto funcione, un punto de interrupción debe establecerse al comienzo de cada método. Ya sea que lo haga manualmente o que el depurador lo haga de manera automática, esos puntos de interrupción se deben configurar para que funcionen.
Entonces, la pregunta realmente es: "Si hay suficiente necesidad de esta funcionalidad, ¿vale la pena construir en el depurador un medio automático para establecer todos esos puntos críticos?". Y la respuesta es "No realmente".
No que yo supiese. Lo mejor que puede hacer es poner un punto de corte en cada método en el archivo o clase. ¿Que estás tratando de hacer? ¿Estás tratando de descubrir qué método está causando que algo cambie? Si es así, quizás un punto de interrupción de datos será más apropiado.
No. O más bien, sí, pero implica establecer un punto de interrupción al comienzo de cada método.
Podría escribir un método de envoltura a través del cual realiza TODAS las llamadas en su aplicación. Luego estableces un punto de interrupción en ese único método. Pero ... estarías loco por hacer tal cosa.
System.Diagnostics.Debugger.Break();
(al comienzo de cada método)
¿No es el método más simple para acercarse a esto simplemente establecer un punto de interrupción en el constructor (suponiendo que solo tiene uno, o cada uno de ellos en el caso de múltiples constructores)?
Esto irrumpirá en la depuración cuando la clase se instancia por primera vez en el caso de un constructor no estático, y en el caso de una clase / constructor estático, interrumpirá la depuración tan pronto como Visual Studio decida inicializar su clase.
Esto ciertamente evita tener que establecer un punto de interrupción en cada método dentro de la clase.
Por supuesto, no continuará introduciéndose en la depuración en el reingreso posterior al código de la clase (suponiendo que esté utilizando el mismo objeto instanciado la próxima vez), sin embargo, si vuelve a crear instancias de un objeto nuevo cada vez desde dentro del código de llamada, puedes simular esto.
Sin embargo, en términos convencionales, no hay una forma simple de establecer un único punto de interrupción en un lugar (por ejemplo) y hacer que se rompa en la depuración cada vez que se ingresa el código de una clase (de cualquier método) (hasta donde yo sé).
Esto funciona bien en WinDbg:
bm exename!CSomeClass::*
(Solo para aclarar, la línea anterior establece un punto de interrupción en todas las funciones de la clase, al igual que lo que pide el OP, sin recurrir a la piratería CRT o macro silliness)
Podría escribir una macro de Visual Studio que obtuviera una lista de todos los métodos de la clase (por ejemplo, leyendo el archivo .map
producido junto con el ejecutable y buscando los nombres de símbolos apropiados (y luego pidiendo esos nombres)), y luego use Breakpoints.add()
para agregar puntos de interrupción programáticamente a esas funciones.
Podría poner un punto de interrupción de memoria en esto y configurarlo para que sea leído. Creo que debería leerse la mayoría de las veces que llamas a una función miembro. No estoy seguro de las funciones estáticas.
Podrías comenzar por introducir algún tipo de Programación Orientada a Aspectos -ver por ejemplo esta explicación- y luego poner un punto de interrupción en el método OnEnter único.
Dependiendo de qué marco AOP elijas, requerirá un poco de decoración en tu código e introducirá un poco de sobrecarga (que puedes eliminar más adelante) pero al menos no necesitarás establecer puntos de interrupción en todas partes. En algunos marcos, incluso podría presentarlo sin cambio de código, solo un archivo XML en el lateral.
Puede usar Debugger.Launch()
y Debugger.Break()
en el ensamblado System.Diagnostics
Si se trata de C ++ de lo que está hablando, entonces probablemente podría salirse con la suya (mucho trabajo) estableciendo un punto de quiebre en el código de preámbulo en el CRT, o escribiendo código que modifique el código de preámbulo para pegar INT 3 allí solo para las funciones generadas desde la clase en cuestión ... Esto, por cierto, PUEDE hacerse en tiempo de ejecución ... Tendría que tener el archivo PE que se ha generado modificarse, posiblemente antes de la reubicación, para guardar todas las interrupciones en ahí...
Mi única otra sugerencia sería escribir una macro que use la macro predefinida __FUNCTION__, en la que busque cualquier función que sea parte de la clase en cuestión, y si es necesario, inserte una macro
__asm { int 3 }
en tu macro para hacer que VS se rompa ... Esto evitará que tengas que establecer puntos de interrupción al comienzo de cada función, pero igual tendrías que hacer una macro llamada, que es mucho mejor, si me preguntas. Creo que leí en algún lado cómo puedes definir o redefinir el código de preámbulo que se llama por función ... Veré qué puedo encontrar.
Creo que podría usar un hack similar para detectar qué ARCHIVO ingresas, pero TODAVÍA tienes que colocar el macro de tu función en todo tu código, o nunca se llamará, y, bueno, eso es más o menos lo que no querías. que hacer.
Suponiendo que solo te interesan los métodos públicos, es decir, cuando los métodos de clase se llaman "desde afuera", volveré a conectar Design by Contract.
Puede adquirir el hábito de escribir sus funciones públicas de esta manera:
public int Whatever(int blah, bool duh)
{
// INVARIANT (i)
// PRECONDITION CHECK (ii)
// BODY (iii)
// POSTCONDITION CHECK (iv)
// INVARIANT (v)
}
Luego puede usar la función Invariant () a la que llamará (i) y establecerá un punto de interrupción en ella . Luego, inspecciona la pila de llamadas para saber de dónde vienes. Por supuesto, también lo llamará (v); si está realmente interesado en solo puntos de entrada, puede usar una función de ayuda para llamar a Invariant desde (i) y desde (v).
Por supuesto, este es un código extra, pero
- De todos modos, es un código útil, y la estructura es repetitiva si usa Diseño por contrato.
- A veces quieres que los puntos de interrupción investiguen algún comportamiento incorrecto, por ejemplo, el estado de objeto no válido, en ese caso los invariantes pueden ser invaluables.
Para un objeto que siempre es válido, la función Invariant () simplemente tiene un cuerpo que devuelve verdadero. Todavía puedes poner un punto de quiebre allí.
Es solo una idea, sin dudas tiene un paso, así que simplemente considérela y úsela si le gusta.
Tal vez podría utilizar un marco AOP como PostSharp para entrar en el depurador siempre que se ingrese un método. Eche un vistazo al breve tutorial en esta página para ver un ejemplo, cómo puede registrar / rastrear cada vez que se ingresa un método.
En lugar de iniciar sesión, en su caso podría colocar la declaración Debugger.Break () en OnEntry-handler. Aunque, el depurador no se detendría en sus métodos, sino en OnEntry-handler (así que no estoy seguro de si esto realmente ayuda).
Aquí hay una muestra muy básica:
La clase de aspecto define un controlador OnEntry, que llama a 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();
}
}
Luego puedo aplicar este aspecto a mi clase, donde quiero que el depurador se rompa siempre que se llame a un método:
[DebugBreak("DebugBreak")]
public class MyClass
{
public MyClass()
{
// ...
}
public void Test()
{
// ...
}
}
Ahora, si construyo y ejecuto la aplicación, el depurador se detendrá en el controlador OnEntry () siempre que se invoque uno de los métodos de MyClass. Todo lo que tengo que hacer entonces, es presionar F10, y estoy en el método de MyClass.
Use Debugger.Break (); (desde el espacio de nombres System.Diagnostics)
Ponlo en la parte superior de cada función que deseas que se "rompa"
void MyFunction()
{
Debugger.Break();
Console.WriteLine("More stuff...");
}
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;
}
en la función de entrar se romperá en el depurador
Macros puede ser tu amigo. Aquí hay una macro que agregará un punto de interrupción a cada método en la clase actual (coloque el cursor en algún lugar de la clase antes de ejecutarlo).
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
Editar: se actualizó para agregar punto de corte por nombre de función, en lugar de número de archivo / línea. Se ''siente'' mejor y será más fácil de reconocer en la ventana de puntos de corte.
Los archivos no tienen existencia en el tiempo de ejecución (considere que las clases parciales no son diferentes, en términos de código, de poner todo en un solo archivo). Por lo tanto, se requiere un enfoque macro (o código en cada método).
Para hacer lo mismo con un tipo (que existe en tiempo de ejecución) se puede hacer, pero es probable que sea muy intrusivo, creando más potencial para heisenbugs. La ruta "más fácil" hacia esto probablemente sea hacer uso de la infraestructura proxy de .NET (ver la implementación de MOQ para un ejemplo del uso del proxy transparente).
Resumen: use una macro, o seleccione todo seguido por establecer punto de corte (ctrl-A, F9).
Esta característica se implementa en VS para C ++ nativo. crtl-B y especifique la ''función'' como "Nombre de clase :: *", esto establece un punto de interrupción al comienzo de cada método en la clase. Los conjuntos de puntos de interrupción se agrupan en la ventana de puntos de interrupción (ctrl-alt-B) para que puedan habilitarse, deshabilitarse y eliminarse como un grupo.
Lamentablemente, la macro es la mejor apuesta para el código administrado.
Joel, la respuesta parece ser "no". No hay una forma sin un punto de corte en cada método.
Para eliminar los puntos de corte establecidos por la respuesta aceptada, agregue otra macro con el siguiente código
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
Método loco usando la reflexión. Consulte la documentación de MethodRental.SwapMethodBody
para obtener más información. En pseudocódigo:
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
}
A continuación, puede pasar el nombre de clase como un argumento de tiempo de ejecución (a través de la línea de comandos, si lo desea) para establecer puntos de interrupción en todos los métodos y constructores de la clase determinada.
Si está dispuesto a usar un macro, entonces la respuesta aceptada de esta pregunta
Debe ser trivialmente convertible a sus necesidades haciendo que la función de búsqueda busque métodos, propiedades y constructores (como se desee), también es muy posible que haya una forma de obtener la misma información de los ide / símbolos que será más estable (aunque quizás un poco más complejo).