En realidad, hay algunas situaciones en las que la declaración throw
no conservará la información de StackTrace. Por ejemplo, en el código de abajo:
try
{
int i = 0;
int j = 12/i; // Line 47
int k = j + 1;
}
catch
{
// do something
// ...
throw; // Line 54
}
El StackTrace indicará que la línea 54 produce la excepción, aunque se planteó en línea 47.
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at Program.WithThrowIncomplete() in Program.cs:line 54
at Program.Main(String[] args) in Program.cs:line 106
En situaciones como la que se ha descrito anteriormente, hay dos opciones para la preseve StackTrace el original:
Llamando al Exception.InternalPreserveStackTrace
Como es un método privado, tiene que ser invocada mediante el uso de la reflexión:
private static void PreserveStackTrace(Exception exception)
{
MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
BindingFlags.Instance | BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
}
I tiene una desventaja de depender de un método privado para preservar la información StackTrace. Se puede cambiar en futuras versiones de .NET Framework. El ejemplo de código anterior y la solución propuesta a continuación se extrajeron del Fabrice MARGUERIE weblog.
Calling Exception.SetObjectData
La técnica más adelante fue sugerido por Anton Tykhyy como respuesta a la pregunta In C#, how can I rethrow InnerException without losing stack trace.
static void PreserveStackTrace (Exception e)
{
var ctx = new StreamingContext (StreamingContextStates.CrossAppDomain) ;
var mgr = new ObjectManager (null, ctx) ;
var si = new SerializationInfo (e.GetType(), new FormatterConverter()) ;
e.GetObjectData (si, ctx) ;
mgr.RegisterObject (e, 1, si) ; // prepare for SetObjectData
mgr.DoFixups () ; // ObjectManager calls SetObjectData
// voila, e is unmodified save for _remoteStackTraceString
}
Aunque, tiene la ventaja de confiar en los métodos públicos sólo sino que también depende de la constructora siguiente excepción (que algunas excepciones desarrolladas por 3 partes no implementan):
protected Exception(
SerializationInfo info,
StreamingContext context
)
En mi situación , Tuve que elegir el primer enfoque, porque las excepciones planteadas por una biblioteca de terceros que estaba usando no implementaron este constructor.
Ese manejo de excepciones es maravilloso. Gracias por compartir. –
No estoy seguro si ese artículo es maravilloso, sugiere probar {// ...} catch (Exception ex) {throw new Exception (ex.Message + "otras cosas"); } es bueno. El problema es que eres completamente incapaz de manejar esa excepción más arriba en la pila, a menos que captes todas las excepciones, un gran no-no (¿estás seguro de que quieres manejar esa OutOfMemoryException?) – ljs
@ljs ¿Ha cambiado el artículo desde que Comente ya que no veo ninguna sección donde lo recomiende. Todo lo contrario, de hecho, dice que no lo haga y le pregunta si también quiere manejar OutOfMemoryException? – RyanfaeScotland