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!
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. –