Warum eine Ausnahme in C # abfangen und erneut auslösen?

557

Ich schaue auf den Artikel C # - Datenübertragungsobjekt über serialisierbare DTOs.

Der Artikel enthält diesen Code:

public static string SerializeDTO(DTO dto) {
    try {
        XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
        StringWriter sWriter = new StringWriter();
        xmlSer.Serialize(sWriter, dto);
        return sWriter.ToString();
    }
    catch(Exception ex) {
        throw ex;
    }
}

Der Rest des Artikels sieht vernünftig und vernünftig aus (für einen Noob), aber dieser Try-Catch-Wurf löst eine WtfException aus ... Ist das nicht genau gleichbedeutend damit, Ausnahmen überhaupt nicht zu behandeln?

Ergo:

public static string SerializeDTO(DTO dto) {
    XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
    StringWriter sWriter = new StringWriter();
    xmlSer.Serialize(sWriter, dto);
    return sWriter.ToString();
}

Oder fehlt mir etwas Grundlegendes zur Fehlerbehandlung in C #? Es ist so ziemlich das gleiche wie Java (minus geprüfte Ausnahmen), nicht wahr? ... Das heißt, beide haben C ++ verfeinert.

Die Frage zum Stapelüberlauf Der Unterschied zwischen dem erneuten Werfen von parameterlosem Fang und dem Nichtstun? scheint meine Behauptung zu unterstützen, dass Try-Catch-Throw ein No-Op ist.


BEARBEITEN:

Nur um es für alle zusammenzufassen, die diesen Thread in Zukunft finden ...

UNTERLASSEN SIE

try {
    // Do stuff that might throw an exception
}
catch (Exception e) {
    throw e; // This destroys the strack trace information!
}

Die Stack-Trace-Informationen können entscheidend sein, um die Grundursache des Problems zu ermitteln!

TUN

try {
    // Do stuff that might throw an exception
}
catch (SqlException e) {
    // Log it
    if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
        // Do special cleanup, like maybe closing the "dirty" database connection.
        throw; // This preserves the stack trace
    }
}
catch (IOException e) {
    // Log it
    throw;
}
catch (Exception e) {
    // Log it
    throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
    // Normal clean goes here (like closing open files).
}

Fangen Sie die spezifischeren Ausnahmen vor den weniger spezifischen (genau wie Java).


Verweise:

Corlettk
quelle
8
Gute Zusammenfassung; Extrapunkte für die Aufnahme des Endblocks.
Fredrik Mörk
Ich möchte hinzufügen, dass Sie den "Wurf" verwenden können; Um noch hilfreicher zu sein, fügen Sie die Parameter hinzu, die vor dem "throw" an die Methode in der e.Data-Auflistung gesendet wurden. Aussage
Michael Bahig
@MickTheWarMachineDesigner (und Teilzeitmaler). Huh? Sie sprechen von Microshite Suckwell-Ausnahmen (wahrscheinlich ab 2005, soweit ich weiß). Ich habe allgemein über die Ausnahmebehandlung gesprochen. Und ja, ich habe einige gelernt, seit ich dies vor fast vier Jahren gepostet habe ... Aber ja, ich gestehe, dass Sie einen gültigen Punkt haben, aber ich denke, Sie haben den wirklichen Punkt verpasst; Wenn du meinen Drift bekommst? Diese Frage bezieht sich auf die GENERALISIERTE Ausnahmebehandlung in C #. und genauer gesagt über das erneute Auslösen von Ausnahmen ... aller Art. Cool?
Corlettk
Bitte ziehen Sie in Betracht, den Abschnitt "Zusammenfassung bearbeiten" in Ihrer Frage auf eine eigene Antwort zu verschieben. Informationen zum Warum finden Sie unter Bearbeiten der Selbstantwort außerhalb der Frage und der in die Frage eingebetteten Antwort .
DavidRR
2
Hat jemand den Teil "Exkremente aufgetreten" nicht bemerkt? es hört sich so an, als wäre der Code für einen Kot gegangen!
Jason Loki Smith

Antworten:

430

Zuerst; Die Art und Weise, wie der Code im Artikel es tut, ist böse. throw exsetzt den Aufrufstapel in der Ausnahme auf den Punkt zurück, an dem sich diese throw-Anweisung befindet; Verlust der Informationen darüber, wo die Ausnahme tatsächlich erstellt wurde.

Zweitens, wenn Sie nur so fangen und erneut werfen, sehe ich keinen Mehrwert. Das obige Codebeispiel wäre throw exohne den Try-Catch genauso gut (oder, angesichts des Bits, sogar noch besser).

Es gibt jedoch Fälle, in denen Sie möglicherweise eine Ausnahme abfangen und erneut auslösen möchten. Die Protokollierung könnte eine davon sein:

try 
{
    // code that may throw exceptions    
}
catch(Exception ex) 
{
    // add error logging here
    throw;
}
Fredrik Mörk
quelle
6
@Fredrick, nur zu Ihrer Information (obwohl Sie wahrscheinlich wissen), wenn Sie dieses exObjekt nicht verwenden möchten, müssen Sie es nicht instanziieren.
Eoin Campbell
78
@Eoin: Wenn es nicht instanziiert wird, ist es ziemlich schwierig, es zu protokollieren.
Sam Axe
30
Ja, ich denke, "böse" ist ungefähr richtig ... betrachten Sie den Fall einer Nullzeigerausnahme, die irgendwo aus einem großen Codekörper ausgelöst wird. Die Nachricht lautet Vanille. Ohne die Stapelverfolgung bleibt "Irgendwo war null". NICHT gut, wenn die Produktion tot ist; und Sie haben KEINE Minuten oder weniger Zeit, um das Flamin-Problem zu lösen und es zu verwerfen oder zu beheben ... Eine gute Ausnahmebehandlung ist Gold wert.
Corlettk
4
Gilt das auch für Java ... "throw" vs. "throw ex"?
JasonStoltz
8
@ Jason, siehe diese Frage . throw exStartet in Java den Stacktrace nicht neu.
Matthew Flaschen
117

Tu das nicht,

try 
{
...
}
catch(Exception ex)
{
   throw ex;
}

Sie verlieren die Stack-Trace-Informationen ...

Entweder tun,

try { ... }
catch { throw; }

ODER

try { ... }
catch (Exception ex)
{
    throw new Exception("My Custom Error Message", ex);
}

Einer der Gründe, warum Sie möglicherweise erneut werfen möchten, ist, wenn Sie verschiedene Ausnahmen behandeln, z

try
{
   ...
}
catch(SQLException sex)
{
   //Do Custom Logging 
   //Don't throw exception - swallow it here
}
catch(OtherException oex)
{
   //Do something else
   throw new WrappedException("Other Exception occured");
}
catch
{
   System.Diagnostics.Debug.WriteLine("Eeep! an error, not to worry, will be handled higher up the call stack");
   throw; //Chuck everything else back up the stack
}
Eoin Campbell
quelle
7
Warum nicht einfach den Fang ganz rauslassen?
AnthonyWJones
3
Es ist immer noch wertvoll, catch {throw; } am Ende einer Liste spezifischer Ausnahmetypen mit der Begründung, dass der Autor den Fall in Betracht gezogen hat, obwohl ein Kommentar ebenfalls ausreichen könnte. Nicht zu raten, wann Sie Code lesen, ist eine gute Sache.
Annakata
87
Aus irgendeinem Grund stört mich der Name der SQLException.
Michael Myers
13
Dieser Haken (Ausnahme) {neue Ausnahme auslösen (...)} sollten Sie niemals tun, nur weil Sie die Ausnahmeinformationen verschleiern und die Ausnahmefilterung im Aufrufstapel unnötig erschweren. Sie sollten nur dann einen Ausnahmetyp abfangen und einen anderen auslösen, wenn Sie eine Abstraktionsschicht implementieren und einen anbieterspezifischen Ausnahmetyp (z. B. SqlException versus XmlException) in einen allgemeineren (z. B. DataLoadingException) umwandeln müssen.
Jammycakes
3
@dark_perfect Sie sollten dieses Argument am Anfang der Methode im Voraus überprüfen und dort die ArgumentNullException auslösen (schnell fehlschlagen).
Andrei Bozantan
56

C # (vor C # 6) unterstützt keine "gefilterten" Ausnahmen von CIL, was VB tut. In C # 1-5 besteht ein Grund für das erneute Auslösen einer Ausnahme darin, dass Sie zum Zeitpunkt von catch () nicht über genügend Informationen verfügen. um festzustellen, ob Sie die Ausnahme tatsächlich abfangen wollten.

In VB können Sie dies beispielsweise tun

Try
 ..
Catch Ex As MyException When Ex.ErrorCode = 123
 .. 
End Try

... die MyExceptions mit unterschiedlichen ErrorCode-Werten nicht behandeln würden. In C # vor Version 6 müssten Sie die MyException abfangen und erneut auslösen, wenn der ErrorCode nicht 123 wäre:

try 
{
   ...
}
catch(MyException ex)
{
    if (ex.ErrorCode != 123) throw;
    ...
}

Seit C # 6.0 können Sie genau wie mit VB filtern :

try 
{
  // Do stuff
} 
catch (Exception e) when (e.ErrorCode == 123456) // filter
{
  // Handle, other exceptions will be left alone and bubble up
}
bzlm
quelle
2
Dave, aber (zumindest in Java) würden Sie keine "generische" MyException auslösen, sondern einen SPEZIFISCHEN Ausnahmetyp definieren und auslösen, damit er im catch-Block nach Typ differenziert werden kann ... Aber ja , wenn Sie nicht der Architekt der Ausnahme sind (ich denke hier an JDBCs SQLException (wieder Java), die ekelhaft allgemein ist und die Methode getErrorCode () enthüllt ... Hmmm ... Sie haben einen Punkt, es ist nur das Ich denke, es gibt einen besseren Weg, wenn möglich. Cheers Mate. Ich schätze Ihre Zeit sehr. Keith.
Corlettk
1
Nun, die Frage lautet "Warum Ausnahmen in C # abfangen und erneut auslösen?", Und dies ist eine Antwort. =] ... und selbst mit speziellen Ausnahmen sind Ausnahmefilter sinnvoll: Betrachten Sie den Fall, in dem Sie beispielsweise eine SqlTimeoutException und eine SqlConnectionResetException behandeln, die beide SqlException sind. Mit Ausnahmefiltern können Sie eine SqlException nur abfangen, wenn es sich um eine dieser beiden handelt. Anstatt Ihren Versuch / Fang mit identischer Behandlung für diese beiden zu überladen, können Sie "SqlException ex abfangen, wenn ex SqlTimeoutException oder ex SqlConnectionResetException ist". (Ich bin übrigens nicht Dave)
bzlm
3
Gefilterte Ausnahmen kommen in C # 6!
Sir Crispalot
14

Mein Hauptgrund für Code wie:

try
{
    //Some code
}
catch (Exception e)
{
    throw;
}

ist so, dass ich einen Haltepunkt im catch haben kann, der ein instanziiertes Ausnahmeobjekt hat. Ich mache das oft beim Entwickeln / Debuggen. Natürlich gibt mir der Compiler eine Warnung zu allen nicht verwendeten E's, und im Idealfall sollten sie vor einem Release-Build entfernt werden.

Sie sind aber nett beim Debuggen.

Peter Mortensen
quelle
1
Ja, ich werde das bezahlen, aber ja, das würdest du nicht im veröffentlichten Code sehen wollen ... ergo: Ich würde mich schämen, es zu veröffentlichen
;-)
25
Dies ist eigentlich nicht erforderlich. In Visual Studio können Sie den Debugger so einstellen, dass er beim Auslösen einer Ausnahme unterbrochen wird, und die Ausnahmedetails werden in einem Inspektorfenster für Sie angezeigt.
Jammycakes
8
Wenn Sie NUR während des Debuggens Code verwenden möchten, verwenden Sie #if DEBUG ... #endif, und Sie müssen diese Zeilen nicht entfernen
Michael Freidgeim
1
Ja, das habe ich selbst ein paar Mal gemacht. Hin und wieder wird man zu einer Veröffentlichung fliehen. @jammycakes Das Problem mit der Unterbrechung der Ausnahme durch Visual Studio ist, dass manchmal die gewünschte Ausnahme nicht die einzige (oder sogar nur eine ihrer Art) ist, die ausgelöst wird. Ich kenne immer noch keine Haltepunktbedingung mit "Pause, wenn ausnahmsweise übersprungen". Bis dahin bleibt dies nützlich. Michael Freidgeim: #if DEBUGum BEIDE herum try {und } catch () {...}ist ein bisschen chaotisch und macht mich ehrlich gesagt mulmig ... Der Vorprozessor ist im Allgemeinen nicht mein Freund.
11

Ein gültiger Grund für das erneute Auslösen von Ausnahmen kann sein, dass Sie der Ausnahme Informationen hinzufügen oder die ursprüngliche Ausnahme in eine eigene Ausnahme einschließen möchten:

public static string SerializeDTO(DTO dto) {
  try {
      XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
      StringWriter sWriter = new StringWriter();
      xmlSer.Serialize(sWriter, dto);
      return sWriter.ToString();
  }
  catch(Exception ex) {
    string message = 
      String.Format("Something went wrong serializing DTO {0}", DTO);
    throw new MyLibraryException(message, ex);
  }
}
edosoft
quelle
Danke, yep Ausnahmeverpackung (besonders verkettet) ist vollkommen gesund ... was nicht gesund ist, fängt eine Ausnahme ab, nur damit Sie die Stapelspur wegschmeißen oder schlimmer noch, essen Sie sie.
Corlettk
10

Ist das nicht genau gleichbedeutend damit, Ausnahmen überhaupt nicht zu behandeln?

Nicht genau, es ist nicht dasselbe. Es setzt den Stacktrace der Ausnahme zurück. Obwohl ich damit einverstanden bin, dass dies wahrscheinlich ein Fehler und damit ein Beispiel für schlechten Code ist.

Arjan Einbu
quelle
8

Sie möchten nicht ex werfen, da dies den Aufrufstapel verliert. Siehe Ausnahmebehandlung (MSDN).

Und ja, der Versuch ... catch macht nichts Nützliches (abgesehen davon, dass der Aufrufstapel verloren geht - es ist also tatsächlich schlimmer - es sei denn, Sie wollten diese Informationen aus irgendeinem Grund nicht offenlegen).

Duncan
quelle
Sie verlieren nicht den gesamten Aufrufstapel, wenn Sie throw ex verwenden. Sie verlieren nur den Teil des Aufrufstapels ab dem Punkt, an dem die Ausnahme weiter oben im Aufrufstapel aufgetreten ist. Sie behalten jedoch den Aufrufstapel von der Methode bei, mit der die Ausnahme ausgelöst wurde, bis zu dem Punkt, an dem der Client sie aufgerufen hat. Es könnte tatsächlich Anwendungsfälle geben, in denen Sie das verwenden würden, oder die guten Leute bei Microsoft hätten es nicht zugelassen. Das heißt, ich habe es nicht benutzt. Ein weiteres Problem ist, dass das Auslösen von Ausnahmen teuer ist. Tun Sie es nur aus einem sehr berechtigten Grund. Protokollierung würde ich für gerechtfertigt halten, etc.
Charles Owen
5

Ein Punkt, den die Leute nicht erwähnt haben, ist, dass .NET-Sprachen zwar nicht wirklich unterscheiden, die Frage , ob man im Falle einer Ausnahme Maßnahmen ergreifen sollte und ob man sie lösen wird, jedoch unterschiedliche Fragen sind. Es gibt viele Fälle, in denen man aufgrund von Ausnahmen Maßnahmen ergreifen sollte, auf deren Lösung man keine Hoffnung hat, und es gibt einige Fälle, in denen alles, was zum "Auflösen" einer Ausnahme erforderlich ist, darin besteht, den Stapel bis zu einem bestimmten Punkt abzuwickeln - es sind keine weiteren Maßnahmen erforderlich .

Aufgrund der allgemeinen Weisheit, dass man nur Dinge "fangen" sollte, die man "handhaben" kann, tut dies eine Menge Code, der Maßnahmen ergreifen sollte, wenn Ausnahmen auftreten. Beispielsweise erhält eine Menge Code eine Sperre, versetzt das geschützte Objekt "vorübergehend" in einen Zustand, der seine Invarianten verletzt, versetzt es dann in einen legitimen Zustand und gibt die Sperre wieder frei, bevor andere das Objekt sehen können. Wenn eine Ausnahme auftritt, während sich das Objekt in einem gefährlich ungültigen Zustand befindet, besteht die übliche Praxis darin, die Sperre aufzuheben, während sich das Objekt noch in diesem Zustand befindet. Ein viel besseres Muster wäre, eine Ausnahme zu haben, die auftritt, während sich das Objekt in einem "gefährlichen" Zustand befindet, und die Sperre ausdrücklich ungültig macht, sodass jeder zukünftige Versuch, sie zu erwerben, sofort fehlschlägt.

In den meisten .NET-Sprachen besteht die einzige Möglichkeit für Code, basierend auf einer Ausnahme Maßnahmen zu ergreifen catch, darin, die betreffende Aktion auszuführen und dann erneut auszuführen, obwohl er weiß, dass die Ausnahme nicht behoben werden kann throw. Ein anderer möglicher Ansatz, wenn es dem Code egal ist, welche Ausnahme ausgelöst wird, ist die Verwendung eines okFlags mit einem try/finallyBlock. Setzen Sie das okFlag auf falsevor dem Block und truevor dem Beenden des Blocks und vor allen returnBlöcken innerhalb des Blocks. Nehmen Sie dann innerhalb an finally, dass okeine Ausnahme aufgetreten sein muss , wenn sie nicht festgelegt ist. Ein solcher Ansatz ist semantisch besser als ein catch/ throw, aber hässlich und weniger wartbar als er sein sollte.

Superkatze
quelle
5

Dies kann nützlich sein, wenn Ihre Programmierung für eine Bibliothek oder DLL funktioniert.

Diese Rethrow-Struktur kann verwendet werden, um den Aufrufstapel gezielt zurückzusetzen, sodass Sie die Ausnahme von der Funktion selbst erhalten, anstatt die von einer einzelnen Funktion innerhalb der Funktion ausgelöste Ausnahme zu sehen.

Ich denke, dies wird nur verwendet, damit die ausgelösten Ausnahmen sauberer sind und nicht in die "Wurzeln" der Bibliothek gehen.

Jackson Tarisa
quelle
3

Ein möglicher Grund für Catch-Throw besteht darin, Ausnahmefilter, die tiefer im Stapel liegen, daran zu hindern, nach unten zu filtern ( zufälliger alter Link ). Aber wenn das die Absicht wäre, würde es dort natürlich einen Kommentar geben, der dies sagt.

Brian
quelle
Ich habe nicht verstanden, worum es Ihnen geht, bis ich den Link gelesen habe ... und ich bin mir immer noch nicht ganz sicher, worum es Ihnen geht ... ich bin mit VB.NET völlig unbekannt. Ich denke, es führt dazu, dass die Summe als "inkonsistent" gemeldet wird, oder? ... Ich bin ein großer Fan von statischen Methoden. Abgesehen davon, dass sie einfach sind, besteht eine geringere Wahrscheinlichkeit von Inkonsistenzen, wenn Sie die Einstellung von Attributen vom Code trennen das macht die eigentliche Arbeit. Der Stapel ist "selbstreinigend".
Corlettk
3
Die Leute erwarten, dass beim Schreiben von "try {Foo ();} finally {Bar ();}" nichts zwischen Foo und Bar läuft. Aber das ist nicht wahr; Wenn Ihr Anrufer einen Ausnahmefilter hinzugefügt hat und es keinen dazwischenliegenden 'catch' gibt und Foo () auslöst, wird ein anderer zufälliger Code von Ihrem Anrufer ausgeführt, bevor Ihr endgültiger (Balken) ausgeführt wird. Dies ist sehr schlecht, wenn Sie Invarianten oder erhöhte Sicherheit gebrochen haben und erwarten, dass sie bis zum endgültigen Zeitpunkt "sofort" wieder normalisiert werden und kein anderer Code die vorübergehende Änderung sieht.
Brian
3

Es hängt davon ab, was Sie im catch-Block tun und ob Sie den Fehler an den aufrufenden Code weitergeben möchten oder nicht.

Sie könnten sagen Catch io.FileNotFoundExeption exund dann einen alternativen Dateipfad oder einen ähnlichen verwenden, aber trotzdem den Fehler auslösen.

Wenn Sie dies Throwstattdessen tun, Throw Exkönnen Sie die vollständige Stapelverfolgung beibehalten. Throw ex startet den Stack-Trace über die throw-Anweisung neu (ich hoffe, das macht Sinn).

Pondidum
quelle
3

Während viele der anderen Antworten gute Beispiele dafür liefern, warum Sie möglicherweise eine Ausnahme erneut auslösen möchten, scheint niemand ein "endgültiges" Szenario erwähnt zu haben.

Ein Beispiel hierfür ist, dass Sie eine Methode haben, bei der Sie den Cursor setzen (z. B. auf einen Wartecursor), die Methode mehrere Austrittspunkte hat (z. B. if () return;) und Sie möchten sicherstellen, dass der Cursor am zurückgesetzt wird Ende der Methode.

Dazu können Sie den gesamten Code in try / catch / finally einbinden. Stellen Sie den Cursor schließlich wieder auf den rechten Cursor. Damit Sie keine gültigen Ausnahmen begraben, werfen Sie sie erneut in den Haken.

try
{
    Cursor.Current = Cursors.WaitCursor;
    // Test something
    if (testResult) return;
    // Do something else
}
catch
{
    throw;
}
finally
{
     Cursor.Current = Cursors.Default;
}
statler
quelle
1
War catchein obligatorischer Teil von try...finallyhistorisch oder spielt es in diesem Beispiel eine funktionale Rolle? - Ich habe es nur noch einmal überprüft und kann es überhaupt try {} finally {}ohne den Fangblock verwenden.
Sebi
2

In dem Beispiel in dem Code, den Sie gepostet haben, macht es in der Tat keinen Sinn, die Ausnahme abzufangen, da nichts an dem Fang getan wird, der nur erneut angezeigt wird. Tatsächlich schadet es mehr als es nützt, wenn der Aufrufstapel verloren geht .

Sie würden jedoch eine Ausnahme abfangen, um im Falle einer Ausnahme eine Logik auszuführen (z. B. das Schließen der SQL-Verbindung der Dateisperre oder nur eine Protokollierung), und diese zurück in den aufrufenden Code zu werfen, um damit umzugehen. Dies ist in einer Geschäftsschicht häufiger als im Front-End-Code, da der Codierer, der Ihre Geschäftsschicht implementiert, möglicherweise die Ausnahme behandelt.

Es ist NICHT sinnvoll, die Ausnahme in dem von Ihnen geposteten Beispiel abzufangen. Mach das nicht so!

Sheff
quelle
1

Entschuldigung, aber viele Beispiele als "verbessertes Design" riechen immer noch schrecklich oder können extrem irreführend sein. Nach dem Versuch {} catch {log; werfen} ist einfach völlig sinnlos. Die Ausnahmeprotokollierung sollte an zentraler Stelle in der Anwendung erfolgen. Ausnahmen sprudeln ohnehin in die Stapelverfolgung. Warum nicht irgendwo in der Nähe der Systemgrenzen protokollieren?

Vorsicht ist geboten, wenn Sie Ihren Kontext (dh DTO in einem Beispiel) nur in die Protokollnachricht serialisieren. Es kann leicht vertrauliche Informationen enthalten, die möglicherweise nicht in die Hände aller Personen gelangen sollen, die auf die Protokolldateien zugreifen können. Und wenn Sie der Ausnahme keine neuen Informationen hinzufügen, sehe ich den Punkt der Ausnahmeumhüllung wirklich nicht. Gutes altes Java hat einen Sinn dafür, es erfordert, dass der Aufrufer weiß, welche Art von Ausnahmen man erwarten sollte, wenn er den Code aufruft. Da Sie dies in .NET nicht haben, hilft das Umschließen in mindestens 80% der Fälle, die ich gesehen habe, nichts.


quelle
Danke für deinen Gedanken, Joe. In Java (und C #, nehme ich an) würde ich gerne eine Annotation auf Klassenebene @FaultBoundary sehen, die ALLE Ausnahmen (einschließlich nicht aktivierter Ausnahmetypen) zwingt, abgefangen oder als ausgelöst deklariert zu werden. Ich würde diese Anmerkung auf öffentlichen Schnittstellen jeder Architekturebene verwenden. Die @FaultBoundary ThingDAO-Schnittstelle kann daher keine Implementierungsdetails wie SQLExceptions, NPEs oder AIOBs verlieren. Stattdessen würde eine "kausale" Stapelverfolgung protokolliert und eine DAOSystemException ausgelöst ... Ich definiere die Systemausnahme als "dauerhaft schwerwiegend".
Corlettk
5
Es gibt viele Gründe, zu fangen, zu protokollieren und dann erneut zu werfen. Insbesondere wenn die Methode mit dem Fangprotokoll Informationen enthält, die Sie verlieren, wenn Sie die Methode verlassen haben. Der Fehler wird möglicherweise später behandelt, aber nicht protokolliert, und Sie haben Informationen zu Fehlern im System verloren.
Andy
1
Hier ist die Data-Eigenschaft der Exception-Klasse nützlich - sie erfasst alle lokalen Informationen für die generische Protokollierung. Dieser Artikel machte mich ursprünglich darauf aufmerksam: blog.abodit.com/2010/03/…
McGuireV10
1

Zusätzlich zu dem, was die anderen gesagt haben, siehe meine Antwort auf eine verwandte Frage, die zeigt, dass das Fangen und erneutes Werfen kein No-Op ist (es ist in VB, aber ein Teil des Codes könnte C # sein, das von VB aufgerufen wird).

erikkallen
quelle
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - Von der Überprüfung
LHIOUI
@HamzaLH, ich stimme zu, dass es keine gut geschriebene Antwort ist, aber es enthält Informationen, die sich von anderen Antworten und positiven Stimmen unterscheiden. Ich verstehe also nicht, warum Sie vorschlagen, es zu löschen? "Kurze Antworten, die zum Thema gehören und eine Lösung geben, sind immer noch Antworten." Von meta.stackexchange.com/questions/226258/…
Michael Freidgeim
Dies ist eine Antwort nur mit Link
LHIOUI
1. Nur-Link-Antworten sollten in Kommentare geändert und nicht gelöscht werden. 2. Es handelt sich um einen Verweis auf eine andere SO-Frage, nicht auf eine externe Site, die im Laufe der Zeit als weniger wahrscheinlich eingestuft wurde. 3. Es hat einige zusätzliche Beschreibungen, die es nicht "nur Link" machen - siehe meta.stackexchange.com/questions/225370/…
Michael Freidgeim
1

Die meisten Antworten sprechen von Szenario-Catch-Log-Rethrow.

Anstatt es in Ihren Code zu schreiben, sollten Sie AOP verwenden, insbesondere Postsharp.Diagnostic.Toolkit mit OnExceptionOptions IncludeParameterValue und IncludeThisArgument

Michael Freidgeim
quelle
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - Aus dem Rückblick
Tony Dong
@ TonyDong, ich stimme zu, dass es keine gut geschriebene Antwort ist, aber es enthält Informationen, die sich von anderen Antworten und positiven Stimmen unterscheiden. Ich verstehe also nicht, warum Sie vorschlagen, es zu löschen? Übrigens ist der Link 5 Jahre später noch gültig. "Kurze Antworten, die zum Thema gehören und eine Lösung geben, sind immer noch Antworten." Von meta.stackexchange.com/questions/226258/…
Michael Freidgeim
Stackoverflow hat nur diesen Vorschlag.
Tony Dong
@ TonyDong, wenn die Antwort nicht absolut nutzlos ist, sollten Sie "Sieht OK" wählen
Michael Freidgeim
0

Das erneute Auslösen von Ausnahmen über throwist nützlich, wenn Sie keinen bestimmten Code zur Behandlung aktueller Ausnahmen haben oder wenn Sie eine Logik zur Behandlung bestimmter Fehlerfälle haben, aber alle anderen überspringen möchten.

Beispiel:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException)
{
    if (numberText.ToLowerInvariant() == "nothing")
    {
        Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
    }
    else
    {
        throw;
    }
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

Es gibt jedoch auch eine andere Möglichkeit , Bedingungsklauseln in catch-Blöcken zu verwenden:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException) when (numberText.ToLowerInvariant() == "nothing")
{
    Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

Dieser Mechanismus ist effizienter als das erneute Auslösen einer Ausnahme, da die .NET-Laufzeit das Ausnahmeobjekt nicht neu erstellen muss, bevor es erneut ausgelöst wird.

Arsen Khachaturyan
quelle