2009-05-08 15 views
15

Independientemente de otras opciones que puedan lograr el mismo resultado (es decir, agregar puntos de interrupción a mano), ¿es posible agregar mediante programación un punto de interrupción en el código fuente de un proyecto de Visual Studio?Aplicar/desactivar puntos de interrupción mediante programación en Visual Studio

Tales como:

try 
{ 
    FunctionThatThrowsErrors(obj InscrutableParameters); 
} 
catch(Exception ex) 
{ 
    Log.LogTheError(ex); 
    AddBreakPointToCallingFunction(); 
} 

De esta forma cuando se ejecuta en depurar la próxima vez, automáticamente se han establecido puntos de corte en todos los puntos que causaron problemas durante la última ejecución.

No digo que sea una forma particularmente útil de depuración. Me pregunto si la capacidad está ahí.

+0

Debe ser, hago esto en C++ todo el tiempo a través de 'if (IsDebuggerPresent()) DebugBreak();', lo tengo en el constructor de varias de mis clases de excepción. –

Respuesta

39

Me inspiró a hurgar con esto, gracias por mantenerme despierto toda la noche. :) Aquí hay una forma en que puedes hacerlo.

Visual Studio tiene un gran soporte de punto de interrupción. Una de las características más interesantes es que puede indicarle que ejecute una macro de Visual Studio cuando se golpea el punto de interrupción. Estas macros tienen acceso completo al entorno de desarrollo, es decir, pueden hacer lo que sea que se pueda hacer manualmente en el teclado, incluida la configuración de otros puntos de interrupción.

Esta solución consiste en 1) poner un try/catch de nivel superior en su programa para detectar todas las excepciones, 2) poner un punto de interrupción en el bloque catch que ejecuta su macro, y 3) hacer que la macro vea la excepción para averiguar de dónde vino, y poner un punto de quiebre allí. Cuando lo ejecuta en el depurador y se produce una excepción, tendrá un nuevo punto de interrupción en la línea ofensiva del código.

Tome este programa de ejemplo:

using System; 

namespace ExceptionCallstack 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       func1(); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine("Oops"); 
       Console.ReadKey(); 
      } 
     } 

     static void func1() 
     { 
      func2(); 
     } 

     static void func2() 
     { 
      func3(); 
     } 

     static void func3() 
     { 
      throw new Exception("Boom!"); 
     } 
    } 
} 

El objetivo es establecer un punto de interrupción en la programación que throw en func3 cuando se ejecuta en el depurador y obtener el error. Para hacer esto, primero crea una nueva macro de Visual Studio (llamé a la mía SetBreakpointOnException). Pega esto en un nuevo módulo MyDebuggerMacros o lo que sea:

Imports System 
Imports EnvDTE 
Imports EnvDTE80 
Imports EnvDTE90 
Imports System.Diagnostics 
Imports System.Text.RegularExpressions 

Public Module DebuggerMacros 

    Sub SetBreakpointOnException() 

     Dim output As String = "" 

     Dim stackTrace As String = DTE.Debugger.GetExpression("e.StackTrace").Value 
     stackTrace = stackTrace.Trim(New Char() {""""c}) 
     Dim stackFrames As String() = Regex.Split(stackTrace, "\\r\\n") 

     Dim r As New Regex("^\s+at .* in (?<file>.+):line (?<line>\d+)$", RegexOptions.Multiline) 
     Dim match As Match = r.Match(stackFrames(0)) 
     Dim file As String = match.Groups("file").Value 
     Dim line As Integer = Integer.Parse(match.Groups("line").Value) 

     DTE.Debugger.Breakpoints.Add("", file, line) 

    End Sub 

End Module 

Una vez que esta macro está en su lugar, vuelve al bloque catch y establecer un punto de interrupción con F9. A continuación, haga clic con el botón derecho en el círculo rojo del punto de interrupción y seleccione "Al golpear ...". En la parte inferior del diálogo resultante hay una opción para indicarle que ejecute una macro: despliega la lista y elige tu macro. Ahora debería obtener nuevos puntos de interrupción cuando su aplicación arroje excepciones no controladas.

Notas y advertencias acerca de esto:

  • Soy no un gurú de expresiones regulares, estoy seguro de que alguien más pueda preparar algo mejor.
  • Esto no maneja las excepciones anidadas (propiedad InnerException) - puede vencer a su cabeza contra eso si lo desea. :) Compruebe si GetExpression ("e.InnerException") y recurse, tal vez.
  • Hace el análisis de texto en la cadena StackTrace de excpetion, análisis de gráficos de objetos no más sofisticado (profundizando en Exception.TargetSite y usando la reflexión). Las advertencias habituales se refieren a la fragilidad de este enfoque.
  • Por alguna razón, parece poner el punto de interrupción en un "espacio alternativo". Una vez que la sesión de depuración inicial finaliza, no verá el nuevo punto de interrupción en su código. Pero está ahí si ejecuta el programa nuevamente en el depurador, y cosas como "Deshabilitar todos los puntos de interrupción" lo afectan. Sería bueno aprender sobre lo que está pasando, si alguien tiene ganas de encontrar la manera de resolverlo. ¿Tal vez hurgando en el archivo .suo?

Espero que ayude!

+0

¡guau! (Quería escribir solo '¡guau!', Pero no permitiría menos de 15 caracteres :) :) –

+0

Sweet Lordy. Si hubiera una forma en que pudiera darte +10, lo haría. – DevinB

+0

Necesito poner un recordatorio en mi teléfono para volver y votar esta respuesta mañana cuando reciba nuevos votos. :-) – Henric

44

Puede llamar al System.Diagnostics.Debugger.Break().

También puede decirle a Visual Studio que se salte todas las excepciones, incluso las tratadas, yendo al menú al Debug->Exceptions... y verificando Thrown en todas partes que actualmente solo marcó "Usuario no controlado".

+0

Antes que nada, (+1) eso es increíble, no tenía idea de que existía. Sin embargo, la documentación indica que "si no se adjunta ningún depurador, se les preguntará a los usuarios si desean adjuntar un depurador". Eso significa que este método podría interrumpir el flujo de ejecución * actual * si se ejecuta sin un depurador. En mi caso, quiero que establezca un punto de interrupción para la próxima vez. Además, la pregunta indicó que quería establecer el punto de interrupción en la función de llamada, porque (presumiblemente) la función de llamada tiene información contextual importante que no se transmitió. – DevinB

+0

No puede cambiar el código después de compilarlo. Eso significa que lo que desea hacer es elevar su punto de interrupción detrás de un indicador de configuración que siempre está marcado y cambiar la configuración en su excepción. Eso es potencialmente MUCHA configuración. La mejor apuesta en este caso es romper el lanzamiento, como muestra mi edición. –

+7

Además, puede verificar Debugger.IsAttached antes de llamar al descanso. –

2

No creo que realmente se puede "añadir un punto de interrupción", pero se puede dar instrucciones al depurador para suspender la ejecución para que pueda comprobar lo que salió mal, llamando System.Diagnostics.Debugger.break()

4

No responde realmente a su pregunta, pero puede hacer que el depurador se rompa en función de las condiciones que configure utilizando Debug.Assert. Entonces, en lugar de decir "la próxima vez que ejecute una función que causó una excepción, corte" puede agregar aserciones a su función para romperlas cuando las condiciones no son las que deberían ser. Después de todo, no hay garantía de que una función lanzará una excepción esta vez solo porque arrojó una excepción la última vez. :)

0

Además, Visual Basic tiene una palabra clave llamada Stop que esencialmente actuará como punto de corte y romperá la ejecución.

+1

Creo que puede haber entendido mal la pregunta. Quiero que el programa en ejecución modifique el archivo pdb, * no * el código fuente. De esa manera, podría ejecutarlo normalmente la primera vez, y ver cómo lo maneja, y luego podría adjuntar un depurador, y ya habría puntos de interrupción configurados en todos los lugares que fallaron la última vez. Su solución Stop * * siempre * detiene la ejecución. – DevinB

Cuestiones relacionadas