c# exception-handling stack-trace targetinvocationexception inner-exception

c# - Cómo volver a generar la excepción interna de una excepción TargetInvocationException sin perder el seguimiento de la pila



exception-handling stack-trace (3)

Debe tener en cuenta por qué .NET envuelve la excepción con una excepción TargetInvocationException en lugar de dejar pasar la excepción original. Hay una buena razón para eso, no es obvio de dónde proviene la verdadera razón para la excepción. ¿Fue porque la llamada a DynamicInvoke () está bloqueada? No es improbable, no hay nada que el compilador pueda hacer para garantizar que se pasaron los argumentos correctos. ¿O el método de objetivo invocado se lanzó solo?

Debe conocer ambos para juzgar la verdadera razón de la excepción. La ocultación intencional de la excepción TargetInvocationException le dará dificultades para diagnosticar el origen del problema si de hecho fue un problema con la llamada DynamicInvoke (). Evita hacer esto.

Tengo muchos métodos que están llamando utilizando Delegate.DynamicInvoke . Algunos de estos métodos hacen llamadas a la base de datos y me gustaría poder capturar una SqlException y no atrapar la TargetInvocationException y cazar a través de sus inners para encontrar lo que realmente salió mal.

Estaba usando este método para volver a lanzar pero borra el seguimiento de la pila:

try { return myDelegate.DynamicInvoke(args); } catch(TargetInvocationException ex) { Func<TargetInvocationException, Exception> getInner = null; getInner = delegate(TargetInvocationException e) { if (e.InnerException is TargetInvocationException) return getInner((TargetInvocationException) e.InnerException); return e.InnerException; }; Exception inner = getInner(ex); inner.PreserveStackTrace(); throw inner; }

El método PreserveStackTrace es un método de extensión que solucioné gracias a otra publicación (no sé lo que realmente hace). Sin embargo, esto tampoco parece preservar la traza:

public static void PreserveStackTrace(this 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); mgr.DoFixups(); }



Si solo desea volver a lanzar una excepción interna conservando su seguimiento de pila, puede hacerlo con un método como este:

public static void Rethrow(this Exception ex) { typeof(Exception).GetMethod("PrepForRemoting", BindingFlags.NonPublic | BindingFlags.Instance) .Invoke(ex, new object[0]); throw ex; }

Esta técnica es utilizada por Rx (y expuesta por ellos como un método de extensión Exception.PrepareForRethrow ) y también es utilizada por el CTP de Async por su sistema de desenvolvimiento automático (sin una API expuesta públicamente).

Tenga en cuenta, sin embargo, que esta técnica no es técnicamente compatible. Esperemos que Microsoft agregue una API oficial para esto en el futuro. Se ha abierto una sugerencia en Microsoft Connect si desea votar por ella.

Actualización: Se ha agregado una API oficial a .NET 4.5: ExceptionDispatchInfo .