In realtà, ci sono alcune situazioni in cui la throw
dichiarazione non conserverà le informazioni StackTrace. Ad esempio, nel codice seguente:
try
{
int i = 0;
int j = 12 / i; // Line 47
int k = j + 1;
}
catch
{
// do something
// ...
throw; // Line 54
}
StackTrace indicherà che la riga 54 ha sollevato l'eccezione, sebbene sia stata sollevata alla riga 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
In situazioni come quella sopra descritta, ci sono due opzioni per preconfigurare lo StackTrace originale:
Chiamata Exception.InternalPreserveStackTrace
Essendo un metodo privato, deve essere invocato usando reflection:
private static void PreserveStackTrace(Exception exception)
{
MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
BindingFlags.Instance | BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
}
Ho uno svantaggio di fare affidamento su un metodo privato per preservare le informazioni StackTrace. Può essere modificato nelle versioni future di .NET Framework. L'esempio di codice sopra e la soluzione proposta sotto sono stati estratti dal blog di Fabrice MARGUERIE .
Chiamata Exception.SetObjectData
La tecnica seguente è stata suggerita da Anton Tykhyy come risposta a In C #, come posso riproporre InnerException senza perdere la domanda di stack stack .
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
}
Sebbene abbia il vantaggio di basarsi solo su metodi pubblici, dipende anche dal seguente costruttore di eccezioni (che alcune eccezioni sviluppate da terze parti non implementano):
protected Exception(
SerializationInfo info,
StreamingContext context
)
Nella mia situazione, ho dovuto scegliere il primo approccio, perché le eccezioni sollevate da una libreria di terze parti che stavo usando non implementavano questo costruttore.