Насправді, є деякі ситуації, в яких цей throw
статтю не буде зберігати інформацію про StackTrace. Наприклад, у наведеному нижче коді:
try
{
int i = 0;
int j = 12 / i; // Line 47
int k = j + 1;
}
catch
{
// do something
// ...
throw; // Line 54
}
StackTrace вкаже, що рядок 54 підвищив виняток, хоча він був піднятий у рядку 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
У таких ситуаціях, як описана вище, є два варіанти попереднього встановлення початкового StackTrace:
Виклик винятку.InternalPreserveStackTrace
Оскільки це приватний метод, його потрібно викликати за допомогою відображення:
private static void PreserveStackTrace(Exception exception)
{
MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
BindingFlags.Instance | BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
}
У мене є недоліком покладатися на приватний метод збереження інформації StackTrace. Його можна змінити в майбутніх версіях .NET Framework. Наведений вище приклад коду та запропоноване рішення нижче були вилучені з веб-журналу Fabrice MARGUERIE .
Виклик винятку.SetObjectData
Наведена нижче методика запропонувала Антон Тихий як відповідь на In C #, як я можу переосмислити InnerException, не втрачаючи питання сліду стека .
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
}
Незважаючи на те, що вона має перевагу покладатися лише на публічні методи, вона також залежить від наступного конструктора винятків (який деякі винятки, розроблені третіми сторонами, не застосовуються):
protected Exception(
SerializationInfo info,
StreamingContext context
)
У моїй ситуації мені довелося обрати перший підхід, оскільки винятки, створені сторонньою бібліотекою, яку я використовував, не реалізували цей конструктор.