Frage

Ich bin auf den Artikel suchen C # - Data Transfer Object auf serializable DTOs.

Der Artikel enthält dieses Stück 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 gesund und angemessen (zu einem Noob), aber das Try-catch-Wurf wirft einen WtfException ... Ist das nicht genau das entspricht nicht Ausnahmen bei allen Umgang mit?

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 bin ich etwas fehlt grundlegende über Fehler in C # Handhabung? Es ist so ziemlich das gleiche wie Java (minus Ausnahmen geprüft), ist es nicht? ... Das heißt, sie beide verfeinert C ++.

Die Frage Stack-Überlauf Der Unterschied zwischen Wieder werfen parameterlose Fang und nichts zu tun? scheint meine Behauptung zu stützen, dass try-catch-Wurf-a no-op.


EDIT:

Nur für jemanden zusammenfassen, die diesen Thread in Zukunft findet ...

NICHT

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 zur Identifizierung der Ursache des Problems von entscheidenden Bedeutung sein!

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 spezifischere Ausnahmen vor den weniger spezifisch denjenigen (wie Java).


Referenzen:

War es hilfreich?

Lösung

Erste; die Art und Weise, dass der Code in dem Artikel es tut, ist das Böse. throw ex wird den Call-Stack in der Ausnahme auf den Punkt zurückgesetzt, wo diese throw-Anweisung ist; verliert die Informationen darüber, wo die Ausnahme tatsächlich erstellt wurde.

Zweitens, wenn Sie nur fangen und wieder werfen so, ich sehe keinen Mehrwert, das Codebeispiel oben würde genauso gut (oder, angesichts der throw ex Bit, noch besser) ohne den try-catch.

Es gibt jedoch Fälle, in denen Sie vielleicht eine Ausnahme fangen und erneut auslösen. Logging könnte einer von ihnen:

try 
{
    // code that may throw exceptions    
}
catch(Exception ex) 
{
    // add error logging here
    throw;
}

Andere Tipps

Tu dies nicht,

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

Sie werden die Stack-Trace Informationen ...

verlieren

Entweder tun,

try { ... }
catch { throw; }

oder

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

Einer der Grund, warum Sie wollen könnte, ist erneut auslösen, wenn Sie verschiedene Ausnahmen sind Handhabung, für 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
}

C # (vor C # 6) unterstützen CIL nicht „gefiltert Ausnahmen“, die VB tut, so in C # 1-5 ein Grund für die Wieder werfen eine Ausnahme ist, dass Sie nicht genug Informationen zum Zeitpunkt der haben Sie catch (), um zu bestimmen, ob die Ausnahme tatsächlich fangen wollten.

Zum Beispiel in VB können Sie tun,

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

..., die nicht MyExceptions mit unterschiedlichen ErrorCode- Werte behandeln würde. In C # vor v6, würden Sie fangen und wieder werfen die MyException, wenn der Error-Code nicht 123 war:

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

Da C # 6.0 können Sie filtern wie bei VB:

try 
{
  // Do stuff
} 
catch (Exception e) when (e.ErrorCode == 123456) // filter
{
  // Handle, other exceptions will be left alone and bubble up
}

für Meinen Hauptgrund mit Code wie:

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

ist, so kann ich einen Haltepunkt in dem Fang habe, die ein instanzierte Ausnahmeobjekt hat. Ich tue dies eine Menge während der Entwicklung / Debugging. Natürlich gibt mir der Compiler eine Warnung an alle nicht verwendeten E ist, und im Idealfall sollten sie vor einem Release-Build entfernt werden.

Sie sind nett während obwohl das Debuggen.

Ein gültiger Grund für Ausnahmen Erneutes Auslösen kann sein, dass Sie Informationen zu der Ausnahme hinzufügen möchten, oder vielleicht die ursprüngliche Ausnahme in einem Ihrer eigenen machen wickeln:

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);
  }
}
  

Ist das nicht genau das entspricht nicht   Behandlung von Ausnahmen überhaupt?

Nicht genau, es ist nicht das gleiche. Es setzt die Stacktrace der Ausnahme. Obwohl ich wahrscheinlich zustimmen, dass dies ein Fehler ist, und somit ein Beispiel für schlechten Code.

Sie wollen nicht ex werfen - da dies den Call-Stack verlieren. Siehe Ausnahmebehandlung (MSDN).

Und ja, die try ... catch tut nichts Brauchbares (abgesehen von dem Call-Stack verlieren - so ist es eigentlich noch schlimmer - es sei denn, aus irgendeinem Grunde Sie diese Informationen nicht aussetzen wollten).

Ein Punkt, dass die Menschen erwähnt haben, ist, dass während .NET-Sprachen wirklich keine richtige Unterscheidung machen, die Frage, ob man sollte handeln , wenn eine Ausnahme auftritt, und ob man will lösen es sind tatsächlich verschiedene Fragen. Es gibt viele Fälle, in denen eine Aktion auf Ausnahmen basieren nehmen soll man hat keine Hoffnung auf Lösung, und es gibt einige Fälle, in denen das alles ist notwendig, um „Entschlossenheit“ eine Ausnahme ist, den Stapel zu einem bestimmten Punkt entspannen - keine weiteren Maßnahmen erforderlich .

Aufgrund der gemeinsamen Weisheit, dass man nur „fängt“ Dinge, die man „verkraftet“, eine Menge Code, die Maßnahmen ergreifen sollte, wenn Ausnahmen auftreten, nicht. Zum Beispiel wird eine Menge Code, um eine Sperre zu erwerben, setzen Sie das bewachte Objekt „vorübergehend“ in einen Zustand, der seine Invarianten verletzt, steckt es dann in einen legitimen Staat widersprechen, und dann die Sperre zurück, bevor jemand anderes das Objekt sehen. Wenn eine Ausnahme auftritt, während sich das Objekt in einem gefährlich-ungültigen Zustand ist, gängige Praxis ist das Schloss mit dem Objekt lösen noch in diesem Zustand. Eineine viel besseren Muster wären eine Ausnahme zu haben, die auftritt, während das Objekt in einem „gefährlichen“ Zustand ist ausdrücklich die Sperre so jeden künftigen Versuch ungültig machen, sie zu erwerben werden sofort scheitern. Der konsequente Einsatz eines solchen Muster würde die Sicherheit der so genannten „Pokemon“ Ausnahmebehandlung erheblich verbessern, was meiner Meinung nach wegen der Code einen schlechten Ruf in erster Linie bekommt die Ausnahmen ohne geeignete Maßnahmen zu ergreifen erste versickern up ermöglicht.

In den meisten .NET-Sprachen, die einzige Möglichkeit für die Code-Maßnahmen zu ergreifen, auf eine Ausnahme basiert es auf catch (obwohl sie weiß, dass es nicht die Ausnahme lösen gehen), die betreffende Aktion durchführen und dann wieder throw) . Ein anderer möglicher Ansatz, wenn Code nicht etwa nicht, was Ausnahme ausgelöst wird, ist eine ok Flagge mit einem try/finally Block zu verwenden; gesetzt die ok Flagge vor dem Block false, und bevor der Block Ausgänge true, und vor jedem return, die innerhalb des Blockes ist. Dann innerhalb finally, davon ausgehen, dass, wenn ok nicht gesetzt ist, muss eine Ausnahme aufgetreten ist. Ein solcher Ansatz ist semantisch besser als ein catch / throw, ist aber hässlich und ist weniger wartbar als es sein sollte.

Ein möglicher Grund zu Wurf zu fangen ist keine Ausnahme Filter tiefer auf den Stack deaktivieren von Filtern nach unten ( zufällig alter Link ). Aber natürlich, wenn das die Absicht war, dort gäbe es einen Kommentar sagen so.

Es hängt davon ab, was Sie im catch-Block tun, und wenn Sie auf die Telefonvorwahl oder den Fehler nicht passieren wollen, sind.

Sie könnten Catch io.FileNotFoundExeption ex sagen und dann einen alternativen Dateipfad verwenden oder so, aber immer noch die Fehler werfen auf.

Auch tun Throw statt Throw Ex ermöglicht es Ihnen, den vollen Stack-Trace zu halten. Throw ex startet den Stack-Trace aus der throw-Anweisung (ich hoffe, das macht Sinn).

Während viele der anderen Antworten liefern gute Beispiele dafür, warum Sie wollen, könnte eine rethrow eine Ausnahme zu fangen, scheint niemand ein ‚endlich‘ Szenario erwähnt zu haben.

Ein Beispiel hierfür ist, wo man ein Verfahren, in dem Sie die Cursor gesetzt (zum Beispiel auf eine Wartecursor) hat das Verfahren mehrere Austrittspunkte (zB if () return;), und Sie wollen, dass die Cursor, um sicherzustellen, Reset am Ende des Verfahrens.

Um dies zu tun, können Sie den gesamten Code wickeln in einem try / catch / finally. Im schließlich setzen Sie den Cursor nach rechts zurück Cursor. Damit Sie alle gültigen Ausnahmen begraben nicht, es in dem Fang erneut auslösen.

try
{
    Cursor.Current = Cursors.WaitCursor;
    // Test something
    if (testResult) return;
    // Do something else
}
catch
{
    throw;
}
finally
{
     Cursor.Current = Cursors.Default;
}

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

Diese rethrow Struktur verwendet werden kann gezielt den Call-Stack zurückgesetzt, so dass anstelle der Ausnahme von einer einzelnen Funktion innerhalb der Funktion geworfen zu sehen, erhalten Sie die Ausnahme von der Funktion selbst.

Ich denke, das nur so verwendet wird, dass die ausgelöste Ausnahmen sauberer sind und geht nicht in die „Wurzeln“ der Bibliothek.

Im Beispiel in dem Code, den Sie gibt es, in der Tat gebucht haben, keinen Sinn, fangen die Ausnahme, da es nichts auf dem Fang getan wird, ist es gerade wieder thown, in der Tat hat es mehr schaden als nützen als den Anruf Stapel verloren.

Sie würden jedoch eine Ausnahme fangen einige Logik (zB Schließen SQL-Verbindung von Dateisperre oder nur einige Protokollierung) im Falle einer Ausnahme den Ball es zurück an den aufrufenden Code zu tun, zu beschäftigen. Dies wäre häufiger in einer Business-Schicht als Front Code Ende, wie Sie die Kodierer Umsetzung Ihrer Business-Schicht behandeln die Ausnahme mögen.

, erneut auf, obwohl die es keinen Sinn, die Ausnahme in dem Beispiel fangen Sie auf dem Laufenden. NICHT es so tun!

Es tut uns Leid, aber viele Beispiele als „verbessertes Design“ immer noch schrecklich riechen oder kann sehr irreführend sein. Mit try {} catch {log; throw} ist nur völlig sinnlos. Ausnahme Protokollierung sollte an zentraler Stelle innerhalb der Anwendung erfolgen. und nahe an den Grenzen des Systems Ausnahmen Blase die Stacktrace ohnehin auf, warum sie nicht irgendwo anmelden?

Vorsicht verwendet werden sollten, wenn Sie Ihren Kontext (das heißt DTO in einem gegebenen Beispiel) serialisiert werden nur in die Log-Nachricht. Es kann leicht sensible Informationen enthalten könnte man nicht die Hände aller Menschen erreichen wollen, die die Protokolldateien zugreifen können. Und wenn Sie fügen keine neuen Informationen zu der Ausnahme, ich wirklich sehe nicht den Punkt der Ausnahme Verpackung. Gute alte Java hat einen Punkt für das, es Anrufer wissen müssen, welche Art von Ausnahmen sollte man erwarten, dann den Code aufrufen. Da Sie dies nicht in .NET haben, Wrapping tun keine gute auf mindestens 80% der Fälle, die ich je gesehen habe.

Zusätzlich zu dem, was die anderen gesagt haben, finden Sie unter meine Antwort auf eine ähnliche Frage, die das nicht eine no-op Fang- und Erneutes Auslösen zeigt (es in VB ist, aber C # VB aufgerufen einige könnte der Code sein).

Die meisten Antworten sprechen über Szenario catch-log-rethrow.

Statt es in Ihrem Code zu schreiben betrachtet AOP zu verwenden, insbesondere

scroll top