На самом деле, есть некоторые ситуации, в которых 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:
Вызов Exception.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.
Вызов Exception.SetObjectData
Приведенный ниже метод был предложен Антоном Тихи в качестве ответа на В 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
)
В моей ситуации мне пришлось выбрать первый подход, потому что исключения, вызванные сторонней библиотекой, которую я использовал, не реализовали этот конструктор.
person
CARLOS LOTH
schedule
01.07.2012