Was sind die Best Practices, die zu beachten sind, wenn Ausnahmen abgefangen und erneut ausgelöst werden? Ich möchte sicherstellen, dass die Exception
Objekt- InnerException
und Stapelverfolgung erhalten bleibt. Gibt es einen Unterschied zwischen den folgenden Codeblöcken in der Art und Weise, wie sie damit umgehen?
try
{
//some code
}
catch (Exception ex)
{
throw ex;
}
Vs:
try
{
//some code
}
catch
{
throw;
}
quelle
ExceptionDispatchInfo.Capture(ex).Throw(); throw;
in .NET +4.5 stackoverflow.com/questions/57383/…Wenn Sie eine neue Ausnahme mit der anfänglichen Ausnahme auslösen, wird auch die anfängliche Stapelverfolgung beibehalten.
quelle
AggregateException
sollte nur für Ausnahmen über aggregierte Operationen verwendet werden. Beispielsweise wird es von den KlassenParallelEnumerable
undTask
der CLR ausgelöst . Die Verwendung sollte wahrscheinlich diesem Beispiel folgen.In einigen Situationen
throw
werden die StackTrace-Informationen in der Anweisung nicht beibehalten. Zum Beispiel im folgenden Code:Die StackTrace zeigt an, dass Zeile 54 die Ausnahme ausgelöst hat, obwohl sie in Zeile 47 ausgelöst wurde.
In Situationen wie der oben beschriebenen gibt es zwei Möglichkeiten, die ursprüngliche StackTrace zu erhalten:
Aufruf der Exception.InternalPreserveStackTrace
Da es sich um eine private Methode handelt, muss sie mithilfe von Reflection aufgerufen werden:
Ich habe den Nachteil, dass ich mich auf eine private Methode verlasse, um die StackTrace-Informationen zu erhalten. Es kann in zukünftigen Versionen von .NET Framework geändert werden. Das obige Codebeispiel und die unten vorgeschlagene Lösung wurden aus dem Weblog von Fabrice MARGUERIE extrahiert .
Aufruf von Exception.SetObjectData
Die folgende Technik wurde von Anton Tykhyy als Antwort auf In C # vorgeschlagen. Wie kann ich InnerException erneut auslösen, ohne die Frage nach der Stapelverfolgung zu verlieren?
Obwohl es den Vorteil hat, sich nur auf öffentliche Methoden zu verlassen, hängt es auch vom folgenden Ausnahmekonstruktor ab (den einige von Drittanbietern entwickelte Ausnahmen nicht implementieren):
In meiner Situation musste ich den ersten Ansatz wählen, da die Ausnahmen, die von einer von mir verwendeten Drittanbieter-Bibliothek ausgelöst wurden, diesen Konstruktor nicht implementiert haben.
quelle
Wenn Sie dies
throw ex
tun, lösen Sie im Wesentlichen eine neue Ausnahme aus und verpassen die ursprünglichen Stack-Trace-Informationen.throw
ist die bevorzugte Methode.quelle
Als Faustregel gilt, das Fangen und Werfen des Basisobjekts zu vermeiden
Exception
. Dies zwingt Sie dazu, bei Ausnahmen etwas schlauer zu sein. Mit anderen Worten, Sie sollten einen expliziten Haken für a haben,SqlException
damit Ihr Bearbeitungscode mit a nichts falsch machtNullReferenceException
.In der realen Welt ist es jedoch auch eine gute Praxis, die Basisausnahme abzufangen und zu protokollieren. Vergessen Sie jedoch nicht, das Ganze zu durchlaufen, um die
InnerExceptions
möglichen Ausnahmen zu erhalten .quelle
Sie sollten immer "throw" verwenden. um die Ausnahmen in .NET neu zu werfen,
Weitere Informationen finden Sie unter http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx
Grundsätzlich hat MSIL (CIL) zwei Anweisungen - "werfen" und "erneut werfen":
Grundsätzlich kann ich den Grund sehen, warum "throw ex" den Stack-Trace überschreibt.
quelle
throw ex;
dass er neu werfen wird - in Java schon! Aber Sie oughta , dass die Informationen hier sind ein Grad eine Antwort zu haben. (Obwohl ich immer noch dieExceptionDispatchInfo.Capture
Antwort von jeuoekdcwzfwccu einhole .)Niemand hat den Unterschied zwischen
ExceptionDispatchInfo.Capture( ex ).Throw()
und einer Ebene erklärtthrow
, also hier ist es. Einige Leute haben jedoch das Problem mit bemerktthrow
.Die vollständige Möglichkeit, eine abgefangene Ausnahme erneut auszulösen, besteht in der Verwendung
ExceptionDispatchInfo.Capture( ex ).Throw()
(nur ab .NET 4.5 verfügbar).Nachfolgend sind die Fälle aufgeführt, die zum Testen erforderlich sind:
1.
2.
3.
4.
Fall 1 und Fall 2 geben Ihnen eine Stapelverfolgung, wobei die Quellcode-Zeilennummer für die
CallingMethod
Methode die Zeilennummer derthrow new Exception( "TEST" )
Zeile ist.In Fall 3 erhalten Sie jedoch eine Stapelverfolgung, bei der die Quellcode-Zeilennummer für die
CallingMethod
Methode die Zeilennummer desthrow
Aufrufs ist. Dies bedeutet, dassthrow new Exception( "TEST" )
Sie keine Ahnung haben, bei welcher Zeilennummer die Ausnahme tatsächlich ausgelöst wurde , wenn die Zeile von anderen Operationen umgeben ist.Fall 4 ist ähnlich wie Fall 2, da die Zeilennummer der ursprünglichen Ausnahme beibehalten wird, jedoch kein echter Neuauswurf ist, da der Typ der ursprünglichen Ausnahme geändert wird.
quelle
throw ex;
und dies ist die beste Antwort von allen.Einige Leute haben tatsächlich einen sehr wichtigen Punkt übersehen - "werfen" und "werfen ex" können dasselbe tun, aber sie geben Ihnen keine entscheidende Information, die die Linie ist, in der die Ausnahme passiert ist.
Betrachten Sie den folgenden Code:
Wenn Sie entweder einen 'Wurf' oder einen 'Wurf-Ex' ausführen, erhalten Sie die Stapelverfolgung, aber die Zeile # wird # 22 sein, sodass Sie nicht herausfinden können, welche Zeile genau die Ausnahme ausgelöst hat (es sei denn, Sie haben nur 1 oder wenige Codezeilen im try-Block). Um die erwartete Zeile Nr. 17 in Ihrer Ausnahme zu erhalten, müssen Sie eine neue Ausnahme mit dem ursprünglichen Ausnahmestapel-Trace auslösen.
quelle
Sie können auch verwenden:
Und alle ausgelösten Ausnahmen sprudeln bis zum nächsten Level, das sie behandelt.
quelle
Ich würde definitiv verwenden:
Das wird Ihren Stapel erhalten.
quelle
throw
; Sie könnten beispielsweise ein Einwegprodukt bereinigen (wo Sie es NUR bei einem Fehler aufrufen) und dann die Ausnahme auslösen.Zu Ihrer Information, ich habe dies gerade getestet und die Stapelverfolgung durch 'throw' gemeldet. ist keine völlig korrekte Stapelverfolgung. Beispiel:
Die Stapelverfolgung zeigt korrekt auf den Ursprung der Ausnahme (gemeldete Zeilennummer), aber die für foo () gemeldete Zeilennummer ist die Zeile des Wurfs; Anweisung, daher können Sie nicht sagen, welcher der Aufrufe von bar () die Ausnahme verursacht hat.
quelle