2012-02-09 17 views
7

El consejo habitual al volver a lanzar una excepción es utilizar una instrucción throw; para conservar el trazado original de la pila. (Example)¿Encuentra dónde se lanzó originalmente la excepción retroprown utilizando el depurador Visual Studio C#?

Sin embargo, cuando intento este ejemplo simple, el depurador de Visual Studio no muestra el seguimiento de pila original.

namespace ExceptionTest 
{ 
    class Program 
    { 
     static void ThrowException() 
     { 
      throw new System.Exception(); // The line that I WANT the debugger to show. 
     } 

     static void Main(string[] args) 
     { 
      try 
      { 
       ThrowException(); 
      } 
      catch (System.Exception) 
      { 
       System.Console.WriteLine("An exception was thrown."); 

       throw; // The line that the debugger ACTUALLY shows. 
      } 
     } 
    } 
} 

¿Cómo puedo usar el depurador para encontrar la fuente original de la excepción?

+0

posible duplicado de [C# volver a lanzar una excepción:? Cómo conseguir la pila de excepción en el IDE] (http://stackoverflow.com/preguntas/4351333/c-sharp-volver a lanzar-an-excepción-how-to-get-la-excepción-stack-en-el-ide) –

Respuesta

10

Su mejor opción es pedir a Visual Studio que rompa la excepción original en lugar de volver a ella desde el seguimiento de la pila. Para ello:

1) Haga clic en la opción de menú 'depuración' 2) Haga clic en 'Excepciones ...' 3) Seleccione 'Excepciones Common Language Runtime' - 'lanzados'

Con este enfoque puede obtener más de lo que realmente desea si se lanzan muchas excepciones. Puede filtrar las excepciones que rompe al expandir la lista de árboles.

Ver imagen:

enter image description here

+0

Esto se aplica incluso cuando no se utiliza 'tirar;' (y en su lugar hacer algo como 'throw ex;'), ¿verdad? Entonces, ¿cuál es la ventaja de usar 'throw;' en lugar de 'throw ex;'? –

+0

La ventana Pila de llamadas no contendrá el punto donde ocurrió la excepción. La propiedad Exception.StackTrace contiene la traza de la pila preservada. Siga los pasos de esta respuesta o lea la propiedad StackTrace de la excepción para determinar dónde se originó la excepción. – JamieSee

+0

@ Jon-Eric Si 'ex tiro;' 'en lugar de tirar;' la propiedad StackTrace en la excepción será no tener el seguimiento de la pila preservado. Siempre volver a lanzar con 'tirar;' o envolviendo la excepción, es decir, 'arrojar nueva ApplicationException ("Mi excepción explicación.", Ex);'. – JamieSee

0

Por cierto, en vb.net, uno puede usar los filtros de excepción en algunas situaciones como ésta, donde uno sabe que no está realmente interesado en la captura de una excepción - sólo encontrar que sucedió Si el código se escribiera en vb.net y se usara un filtro para capturar la excepción (probablemente haciendo la salida misma dentro del bloque 'finally') no habría un "catch and rethrow" - el cursor saltaría a la fuente de la excepción original (como una bonificación, vs interrumpiría el flujo del programa antes de que se produjera el desenrollado de la pila). Tenga en cuenta que se puede optar por tener una trampa vs cada vez que se lanza una excepción en particular, ya sea que se capture o no, pero a veces uno solo está interesado en algunos de los lugares donde se lanza una excepción, en lugar de todos.

1

La mejor solución que he encontrado es escribir la callstack Exception en el Debug.Console y luego dejar que el analizador de la línea de código incorporado en Visual Studio proporcione la navegación.

Me pareció muy útil cuando se trata de excepciones no controladas en el dominio de aplicación y WPF Dispatcher como Visual Studio siempre se rompe demasiado tarde.

base de un artículo sobre Code Project, he modificado que da salida a la Console como un solo bloque de texto - en lugar de la línea por línea - que era necesario tengo registro también escrito al Console.

Uso

public void ReportException(Exception exception) 
{ 
    if (Debugger.IsAttached) 
    { 
     DebugHelper.PrintExceptionToConsole(exception); 
     Debugger.Break(); 
    } 

    // ... 

} 

Fuente

public static class DebugHelper 
{ 
    // Original idea taken from the CodeProject article 
    // http://www.codeproject.com/Articles/21400/Navigating-Exception-Backtraces-in-Visual-Studio 

    private static readonly string StarSeparator = new String('*', 80); 
    private static readonly string DashSeparator = new String('-', 80); 
    private const string TabString = " "; 

    /// <summary> 
    /// Prints the exception using a format recognized by the Visual Studio console parser. 
    /// Allows for quick navigation of exception call stack. 
    /// </summary> 
    /// <param name="exception">The exception.</param> 
    public static void PrintExceptionToConsole(Exception exception) 
    { 
     using (var indentedTextWriter = new IndentedTextWriter(Console.Out, TabString)) 
     {     
      var indentLevel = 0; 
      while (exception != null) 
      { 
       indentedTextWriter.Indent = indentLevel; 
       indentedTextWriter.Write(FormatExceptionForDebugLineParser(exception)); 
       exception = exception.InnerException; 
       indentLevel++; 
      } 
     } 
    } 

    private static string FormatExceptionForDebugLineParser(Exception exception) 
    { 
     StringBuilder result = new StringBuilder(); 

     result.AppendLine(StarSeparator); 
     result.AppendLineFormat(" {0}: \"{1}\"", exception.GetType().Name, exception.Message); 
     result.AppendLine(DashSeparator); 

     // Split lines into method info and filename/line number 
     string[] lines = exception.StackTrace.Split(new string[] { " at " }, StringSplitOptions.RemoveEmptyEntries) 
               .Select(x => x.Trim()) 
               .Where(x => !String.IsNullOrEmpty(x)) 
               .ToArray(); 

     foreach (var line in lines) 
     { 
      string[] parts = line.Split(new string[] { " in " }, StringSplitOptions.RemoveEmptyEntries); 
      string methodInfo = parts[0]; 
      if (parts.Length == 2) 
      { 
       string[] subparts = parts[1].Split(new string[] { ":line " }, StringSplitOptions.RemoveEmptyEntries); 
       result.AppendLineFormat(" {0}({1},1): {2}", subparts[0], Int32.Parse(subparts[1]), methodInfo); 
      } 
      else 
       result.AppendLineFormat(" {0}", methodInfo); 
     } 

     result.AppendLine(StarSeparator); 

     return result.ToString(); 
    } 

} 

Para utilizar el como es, también necesitará el método anterior, Extensión de abajo y agregar el espacio de nombres para System.CodeDom.CompilerIndentedTextWriter.

Método de extensión

/// <summary> 
/// Appends the string returned by processing a composite format string followed by the default line terminator. 
/// </summary> 
/// <param name="sb">The StringBuilder.</param> 
/// <param name="format">The format.</param> 
/// <param name="args">The args.</param> 
public static void AppendLineFormat(this StringBuilder sb, string format, params object[] args) 
{ 
    sb.AppendFormat(format, args); 
    sb.AppendLine(); 
} 
1

Usted puede utilizar el atributo DebuggerNonUserCode.

Ver http://blogs.msdn.com/b/jmstall/archive/2007/02/12/making-catch-rethrow-more-debuggable.aspx

El ejemplo se convierte de esta manera:

namespace ExceptionTest 
{ 
    class Program 
    { 
     static void ThrowException() 
     { 
      throw new System.Exception(); // The line that I WANT the debugger to show. 
     } 

     [DebuggerNonUserCode()] 
     static void Main(string[] args) 
     { 
      try 
      { 
       ThrowException(); 
      } 
      catch (System.Exception) 
      { 
       System.Console.WriteLine("An exception was thrown."); 

       throw; // The line that the debugger ACTUALLY shows. 
      } 
     } 
    } 
} 
Cuestiones relacionadas