2009-10-18 8 views
13

Entender la diferencia entre tiro ex y tiro, ¿Por qué el StackTrace original se preserva en este ejemplo:StackTrace originales/LINENUMBERS en Excepciones .NET

static void Main(string[] args) 
    { 
     try 
     { 
      LongFaultyMethod(); 
     } 
     catch (System.Exception ex) 
     { 
      Console.WriteLine(ex.StackTrace); 
     } 
    } 

    static void LongFaultyMethod() 
    { 
     try 
     { 
      int x = 20; 
      SomethingThatThrowsException(x); 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

    static void SomethingThatThrowsException(int x) 
    { 
     int y = x/(x - x); 
    } 

Pero no en éste:

static void Main(string[] args) 
    { 
     try 
     { 
      LongFaultyMethod(); 
     } 
     catch (System.Exception ex) 
     { 
      Console.WriteLine(ex.StackTrace); 
     } 
    } 

    static void LongFaultyMethod() 
    { 
     try 
     { 
      int x = 20; 
      int y = x/(x - 20); 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

El segundo escenario está produciendo la misma salida que arrojar ex haría?

En ambos casos, uno espera ver el número de línea donde y se inicializa.

Respuesta

14

No estoy seguro de si esta limitación está dentro del lenguaje C#, la CLI o la implementación de Microsoft de estos, pero su segundo ejemplo es un caso donde se requiere una llamada explícita al Exception.InternalPreserveStackTrace como se documenta en la siguiente publicación. Dado que este método es internal, generalmente debe llamarse mediante reflexión. Los problemas de rendimiento involucrados en esto pueden aliviarse casi por completo al crear un Action<Exception> para la llamada, como se muestra al final de esta respuesta.

Referencia: Rethrowing exceptions and preserving the full call stack trace

Editar: Después de reexaminar ECMA-335 de partición que §12.4.2 (manejo de excepciones) y la partición III §4.24 (volver a lanzar), ahora creo que el comportamiento que está viendo es una error semántico en el CLR (implementación de Microsoft de la CLI). La única referencia específica al comportamiento es "A rethrow no cambia el seguimiento de la pila en el objeto". En el caso descrito aquí, el re-lanzamiento está de hecho alterando la traza de la pila, por lo que el PreserveStackTrace piratea una solución para una falla conocida de CLR.

static void LongFaultyMethod() 
{ 
    try 
    { 
     int x = 20; 
     int y = x/(x - 20); 
    } 
    catch (Exception ex) 
    { 
     PreserveStackTrace(ex); // <-- add this line 
     throw; 
    } 
} 

PreserveStackTrace aquí es una optimización de la de que la entrada de blog:

private static readonly Action<Exception> _internalPreserveStackTrace = 
    (Action<Exception>)Delegate.CreateDelegate(
     typeof(Action<Exception>), 
     typeof(Exception).GetMethod(
      "InternalPreserveStackTrace", 
      BindingFlags.Instance | BindingFlags.NonPublic)); 

public static void PreserveStackTrace(Exception e) 
{ 
    _internalPreserveStackTrace(e); 
} 
+0

Esto es genial, gracias por la información. – Nariman

3

Porque en el segundo ejemplo, está volviendo a lanzar la excepción del mismo método. En primer lugar, se lanza desde un método diferente por eso. En un alcance de método, el seguimiento de pila puede ser solo uno.

Haga lo siguiente, la mejor manera es siempre envolver una excepción dentro de una nueva excepción, para que pueda ver la profundidad de la excepción.

"Si volver a lanzar ha estado en expedido en el mismo método (seguimiento de la pila excepción sólo tiene una línea de información del número de por método, nunca se ve seguimiento de la pila que en el Método A, en la línea número 2 excepción fue arrojado y luego en mismo Método a, se relanza de la línea número 17, sólo contendrá último número línea desde donde excepción fue relanza"

try   
{    
    int x = 20;    
    int y = x/(x - 20);   
}   
catch (Exception ex)   
{    
    // do something here.. like log or something 
    throw new Exception("Internal Exception", ex);   
} 
+0

entiendo que esta es una solución temporal que funciona, pero todavía no estoy entender por qué el volver a lanzar en el El segundo ejemplo no debe tener el número de línea correcto. – Sam

+0

No es una solución. Es la forma correcta de hacerlo ... – awe

+0

@ Akash Kava: ¿Tiene alguna referencia?No estoy seguro de haber entendido completamente la pregunta del OP. –

Cuestiones relacionadas