Ist es besser, dies zu tun:
try
{
...
}
catch (Exception ex)
{
...
throw;
}
Oder dies:
try
{
...
}
catch (Exception ex)
{
...
throw ex;
}
Erfüllen sie dieselbe Aufgabe? Ist das eine besser als das andere?
Ist es besser, dies zu tun:
try
{
...
}
catch (Exception ex)
{
...
throw;
}
Oder dies:
try
{
...
}
catch (Exception ex)
{
...
throw ex;
}
Erfüllen sie dieselbe Aufgabe? Ist das eine besser als das andere?
Sie sollten immer die folgende Syntax verwenden, um eine Ausnahme erneut auszulösen. Andernfalls werden Sie den Stack-Trace verstopfen:
throw;
Wenn Sie den Trace ausdrucken, der aus throw ex
Sie werden sehen, dass es an dieser Anweisung endet und nicht an der eigentlichen Quelle der Ausnahme.
Grundsätzlich sollte es als Straftatbestand gelten, die throw ex
.
Wenn eine Ausnahme, die von einer anderen Stelle (AggregateException, TargetInvocationException) oder vielleicht von einem anderen Thread kommt, erneut ausgelöst werden muss, sollte man sie auch nicht direkt auslösen. Stattdessen gibt es die ExceptionDispatchInfo die alle notwendigen Informationen bewahrt.
try
{
methodInfo.Invoke(...);
}
catch (System.Reflection.TargetInvocationException e)
{
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(e.InnerException).Throw();
throw; // just to inform the compiler that the flow never leaves the block
}
Ich bevorzuge die Verwendung von
try
{
}
catch (Exception ex)
{
...
throw new Exception ("Add more context here", ex)
}
Dadurch wird der ursprüngliche Fehler beibehalten, aber Sie können mehr Kontext hinzufügen, z. B. eine Objekt-ID, eine Verbindungszeichenfolge und Ähnliches. Oft hat mein Ausnahmeberichterstattungstool fünf verkettete Ausnahmen zu melden, die jeweils mehr Details enthalten.
Wenn Sie eine Ausnahme auslösen mit aus eine Variable (das erste Beispiel), so enthält die Stack-Trace die ursprüngliche Methode, die die Ausnahme ausgelöst hat.
Im zweiten Beispiel wird der Stack-Trace so geändert, dass er die aktuelle Methode widerspiegelt.
Ejemplo:
static string ReadAFile(string fileName) {
string result = string.Empty;
try {
result = File.ReadAllLines(fileName);
} catch(Exception ex) {
throw; // This will show ReadAllLines in the stack trace
throw ex; // This will show ReadAFile in the stack trace
}
Ich stimme zu, dass man in den meisten Fällen entweder eine einfache throw
um so viele Informationen wie möglich darüber zu erhalten, was schief gelaufen ist, oder Sie wollen eine neue Ausnahme auslösen, die das als innere Ausnahme enthalten kann oder nicht, je nachdem, wie wahrscheinlich es ist, dass Sie etwas über die inneren Ereignisse wissen wollen, die sie verursacht haben.
Es gibt jedoch eine Ausnahme. Es gibt mehrere Fälle, in denen eine Methode eine andere Methode aufruft und eine Bedingung, die beim inneren Aufruf eine Ausnahme verursacht, als dieselbe Ausnahme beim äußeren Aufruf betrachtet werden sollte.
Ein Beispiel ist eine spezialisierte Sammlung, die durch Verwendung einer anderen Sammlung implementiert wird. Sagen wir, es ist eine DistinctList<T>
die eine Hülle aus List<T>
, lehnt aber doppelte Einträge ab.
Wenn jemand anruft ICollection<T>.CopyTo
auf Ihrer Sammelklasse, könnte es ein direkter Aufruf von CopyTo
auf die innere Auflistung (wenn sagen, alle benutzerdefinierten Logik nur auf das Hinzufügen zu der Auflistung angewendet, oder es einrichten). Die Bedingungen, unter denen dieser Aufruf zu einem Fehler führen würde, sind genau die gleichen Bedingungen, unter denen Ihre Sammlung zu einem Fehler führen sollte, um mit der Dokumentation von ICollection<T>.CopyTo
.
Sie könnten die Ausnahme aber auch einfach nicht abfangen und sie durchlaufen lassen. Hier jedoch erhält der Benutzer eine Ausnahme von List<T>
wenn sie etwas auf einer DistinctList<T>
. Es ist nicht das Ende der Welt, aber Sie sollten diese Implementierungsdetails vielleicht ausblenden.
Sie können aber auch selbst eine Überprüfung vornehmen:
public CopyTo(T[] array, int arrayIndex)
{
if(array == null)
throw new ArgumentNullException("array");
if(arrayIndex < 0)
throw new ArgumentOutOfRangeException("arrayIndex", "Array Index must be zero or greater.");
if(Count > array.Length + arrayIndex)
throw new ArgumentException("Not enough room in array to copy elements starting at index given.");
_innerList.CopyTo(array, arrayIndex);
}
Das ist nicht der schlechteste Code, denn es ist eine Standardvorlage und wir können ihn wahrscheinlich einfach von einer anderen Implementierung von CopyTo
wo es sich nicht um eine einfache Durchleitung handelte und wir es selbst implementieren mussten. Trotzdem ist es eine unnötige Wiederholung der genau dasselbe Kontrollen, die in folgenden Bereichen durchgeführt werden sollen _innerList.CopyTo(array, arrayIndex)
Das einzige, was unserem Code hinzugefügt wurde, sind 6 Zeilen, in denen ein Fehler auftreten könnte.
Wir könnten das überprüfen und einpacken:
public CopyTo(T[] array, int arrayIndex)
{
try
{
_innerList.CopyTo(array, arrayIndex);
}
catch(ArgumentNullException ane)
{
throw new ArgumentNullException("array", ane);
}
catch(ArgumentOutOfRangeException aore)
{
throw new ArgumentOutOfRangeException("Array Index must be zero or greater.", aore);
}
catch(ArgumentException ae)
{
throw new ArgumentException("Not enough room in array to copy elements starting at index given.", ae);
}
}
Im Hinblick auf den neu hinzugefügten Code, der möglicherweise fehlerhaft sein könnte, ist dies sogar noch schlimmer. Und von den inneren Ausnahmen haben wir nichts. Wenn wir ein Null-Array an diese Methode übergeben und eine ArgumentNullException
werden wir nichts lernen, wenn wir die innere Ausnahme untersuchen und erfahren, dass ein Aufruf von _innerList.CopyTo
wurde ein Null-Array übergeben und warf ein ArgumentNullException
.
Hier können wir alles machen, was wir wollen:
public CopyTo(T[] array, int arrayIndex)
{
try
{
_innerList.CopyTo(array, arrayIndex);
}
catch(ArgumentException ae)
{
throw ae;
}
}
Jede der Ausnahmen, die wir erwarten zu werfen, wenn der Benutzer es mit falschen Argumenten aufruft, wird korrekt von diesem rethrow ausgelöst werden. Wenn es einen Fehler in der hier verwendeten Logik gibt, dann in einer von zwei Zeilen - entweder haben wir uns geirrt, als wir entschieden, dass dies ein Fall ist, in dem dieser Ansatz funktioniert, oder wir haben uns geirrt, als wir ArgumentException
als den gesuchten Ausnahmetyp. Das sind die einzigen beiden Fehler, die der catch-Block haben kann.
Jetzt. Ich bin nach wie vor der Meinung, dass man in den meisten Fällen entweder eine einfache throw;
oder Sie möchten Ihre eigene Ausnahme konstruieren, um das Problem aus der Sicht der betreffenden Methode besser zu erfassen. Es gibt Fälle wie den obigen, in denen ein solches Zurückwerfen sinnvoller ist, und es gibt viele andere Fälle. Zum Beispiel, um ein ganz anderes Beispiel zu nehmen, wenn ein ATOM-Dateireader mit einer FileStream
und ein XmlTextReader
einen Dateifehler oder ungültiges XML empfängt, dann wird es vielleicht genau die gleiche Ausnahme auslösen wollen, die es von diesen Klassen erhalten hat, aber es sollte für den Aufrufer so aussehen, dass es AtomFileReader
die eine FileNotFoundException
o XmlException
Sie könnten also Kandidaten für eine ähnliche Umgestaltung sein.
Wir können auch beides kombinieren:
public CopyTo(T[] array, int arrayIndex)
{
try
{
_innerList.CopyTo(array, arrayIndex);
}
catch(ArgumentException ae)
{
throw ae;
}
catch(Exception ex)
{
//we weren't expecting this, there must be a bug in our code that put
//us into an invalid state, and subsequently let this exception happen.
LogException(ex);
throw;
}
}
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.