2010-12-04 16 views
17

Ha habido un debate aquí sobre la forma correcta de volver a lanzar una excepción. Esta pregunta, en cambio, trata de cómo obtener un comportamiento útil de Visual Studio cuando se usa Rethrow.Reanudar C# una excepción: cómo obtener la pila de excepciones en el IDE?

consideran este código:

static void foo() { 
     throw new Exception("boo!"); 
    } 

    static void Main(string[] args) { 
     try { 
      foo(); 
     } catch (Exception x) { 
      // do some stuff 
      throw; 
     } 
    } 

La excepción que sale tiene el seguimiento de la pila correcta, mostrando foo() como la fuente de la excepción. Sin embargo,, la ventana de pila de llamadas GUI solo muestra Main, mientras que esperaba que mostrara la pila de llamadas de la excepción, todo el camino hasta foo.

Cuando no hay vuelta atrás, puedo usar la GUI para navegar rápidamente por la pila de llamadas para ver qué llamada provocó la excepción y cómo llegamos allí.

Con el relanzamiento me gustaría poder hacer lo mismo. En cambio, la pila de llamadas que muestra la GUI no me sirve. Tengo que copiar los detalles de la excepción en el portapapeles, pegarlo en el Bloc de notas y luego navegar manualmente a cualquier función de la pila de llamadas que me interese.

Por cierto, obtengo el mismo comportamiento si agrego [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] o si cambio la captura a solo catch (Exception).

Mi pregunta es: dado que el código que tengo utiliza el re-lanzamiento, ¿alguien puede sugerir una forma conveniente de navegar por la pila de llamadas asociada con la excepción? Estoy usando Visual Studio 2010.

+0

¿Por qué Regeneración de la excepción? ¿Hay más código en la cláusula 'catch' que no incluiste aquí? De lo contrario, creo que su solución es simplemente no atrapar la excepción. –

+1

Robert, este es un fragmento mínimo para ilustrar el problema. El código real hace algo de trabajo antes de volver a lanzar. – redtuna

Respuesta

11

Las roturas del depurador en el throw en Main porque esa excepción no se ha manejado. Por defecto, el depurador solo se dividirá en excepciones no controladas. Una vez que se haya detenido en Main, la pila de llamadas para la excepción original de foo está presente en la excepción, pero se ha perdido todo el otro contexto (por ejemplo, locales, estado de pila/memoria).

Parece que usted quiere que el depurador para romper en el throw en foo, por lo que debe decirle al depurador de romper sobre las excepciones de primera oportunidad:

  1. de depuración »Excepciones ... (Ctrl +Alt +E)
  2. de verificación "Arrojado" de los tipos de excepción que le interesan (en este caso, excepciones Commange Language Runtime)
  3. Haga clic en OK
  4. iniciar la depuración

En este caso, el depurador se interrumpirá inmediatamente cuando foo se produce una excepción. Ahora puede examinar la pila, los locales, etc., en el contexto de la excepción original. Si continúa la ejecución (F5), el depurador se volverá a interrumpir en el nuevo lanzamiento en Main.

Tomando otro enfoque, si está ejecutando VS2010 Ultimate, también puede usar IntelliTrace para "depurar hacia atrás" para ver parámetros, subprocesos y variables en el momento de la excepción. Ver this MSDN article para más detalles. (Divulgación completa: trabajo en un equipo estrechamente relacionado con IntelliTrace).

+1

Gracias, eso puede ayudar en algunos casos de hecho. El problema es que en mi caso, hay muchas excepciones lanzadas con el tiempo, y solo me interesan las pocas que se volverán a lanzar. Mirar cada excepción lanzada sería más trabajo que copiar/pegar la pila de llamadas como lo estoy haciendo ahora. Esperaba una forma fácil de navegar la pila de llamadas de la excepción, incluso si se pierde parte del estado asociado. – redtuna

+1

@redtuna: vea la edición al final de mi publicación (podría ser útil si está utilizando VS2010 Ultimate). Además, ¿las excepciones lanzadas son todas del mismo tipo? De lo contrario, puede especificar los tipos de las excepciones que no le interesan en el cuadro de diálogo Excepciones, y luego desmarque la casilla "Lanzado" para evitar que el depurador las rompa. Si las excepciones son todas del mismo tipo, entonces sí, es mucho más difícil. –

+2

¡IntelliTrace luce impresionante! Parece que eso es lo más cerca que hemos llegado a nuestro objetivo con las herramientas que tengo aquí, así que estoy aceptando tu respuesta (aunque la respuesta de Athari podría ser mejor para otras personas). – redtuna

1

No es que debes volver a tiro, pero here 'sa blog acerca de cómo conservar el seguimiento de la pila, en esencia se reduce a lo siguiente:

private static void PreserveStackTrace(Exception exception) 
{ 
    MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace", 
    BindingFlags.Instance | BindingFlags.NonPublic); 
    preserveStackTrace.Invoke(exception, null); 
} 

... 
catch (Exception ex) 
{ 
    // do something 
    // ... 
    PreserveStackTrace(ex); 
    throw; 
} 
+2

Gracias, pero eso no resuelve mi problema en particular. Este código, como explica la publicación del blog, ayuda a obtener el seguimiento correcto de la pila en la excepción para el caso especial en el que la excepción original y la captura están en el mismo método. En mi caso, la excepción tiene el rastro correcto de la pila: el problema es que no sé cómo usar la GUI para navegar ese rastro de la pila. – redtuna

8

Si utiliza ReSharper, puede copiar al portapapeles StackTrace excepción, a continuación, elija en el menú: ReSharper> Herramientas> Navegar Seguimiento de la pila (Ctrl + E, T). Mostrará stacktrace con ubicaciones clicables, por lo que podrá navegar rápidamente.

http://www.jetbrains.com/resharper/webhelp/images/Reference__Windows__Stack_Trace_Explorer.png

Esta característica también es muy útil durante la excavación a través de los registros de los usuarios (si se registran stacktraces de excepciones).

+0

¡Agradable! No tengo resharper, pero esa es una característica increíble. Parece que aceleraría las cosas bien para mí. – redtuna

+2

@redtuna ReSharper es imprescindible para los desarrolladores de C#. Acelera muchas tareas varias veces. – Athari

0

Mike Stall ha dado un great and simple solution a su problema:

Marcar los métodos donde volver a lanzar la excepción con el atributo [DebuggerNonUserCode]

El IDE se consideran este no es su código y no se romperán el depurador en dicho lugar, y en su lugar mirará más allá en la pila, mostrando el próximo re-lanzamiento o el lugar de excepción inicial.

(si la siguiente volver a lanzar también es molesto, marcarlo como [DebuggerNonUserCode] así, etc ...)

Cuestiones relacionadas