Frage Wirf eine C # -Ausnahme vom gleichen Typ wie die gefangene?


Warum (wenn überhaupt) ist das eine schlechte Idee?

class Program
{
  static void Main(string[] args)
  {
     try
     {
        throw new NotImplementedException("Oh dear");
     }
     catch (Exception ex)
     {
        throw NewException("Whoops", ex);
     }
  }

  // This function is the salient bit here
  public static Exception NewException(String message, Exception innerException)
  {
     return Activator.CreateInstance(innerException.GetType(), message, innerException) as Exception;
  }
}

Das wichtige hier ist, dass die Funktion eine Ausnahme vom selben Typ wie die "innere Ausnahme" erzeugt.

Ich denke ... "Oh ... eine Ausnahme ist aufgetreten. Ich kann es hier nicht wirklich handhaben, aber ich kann einige zusätzliche Informationen hinzufügen und erneut werfen. Vielleicht kann ein anderer Handler, weiter oben in der Anrufkette, damit umgehen es."

Ein möglicher Fall könnte eine Art SQL-Fehler sein. Ich bin vielleicht nicht in der Lage, die Ausnahme zum Zeitpunkt des Aufrufs zu behandeln, aber ich möchte vielleicht zusätzliche "Kontext" -Informationen hinzufügen, wie "Ich habe das angerufen und das weitergegeben".

Es scheint, als ob es nützlich sein könnte, die Aufrufkette als Ausnahme des Typs, der ursprünglich ausgelöst wurde, im Gegensatz zu "Exception" oder "ApplicationException" zu übergeben. Ich weiß, dass ich meine eigenen speziellen Ausnahmeklassen erstellen konnte, aber es scheint, dass es nichts viel hinzufügt, wenn Sie bereits eine nette spezifische Ausnahme haben.

Natürlich könnte ich mich irren. Es könnte eine sehr nützliche Sache sein ... aber eine kleine Stimme deutet nicht darauf hin.

----- bearbeiten -----

Erwägen Sie die Auswirkungen der folgenden zwei Funktionen (mit dem obigen Code):

Das ... zu oft gesehen:

  static int SalesTotal(int customerNumber)
  {
     try
     {
        throw new DivideByZeroException(); // something you didn't expect
     }
     catch (Exception ex)
     {
        throw new ApplicationException("Unable to calculate sales for customer " + customerNumber, ex);
     }
  }

versus dies ...

  static int SalesTotal(int customerNumber)
  {
     try
     {
        throw new DivideByZeroException(); // something you didn't expect
     }
     catch (Exception ex)
     {
        throw NewException("Unable to calculate sales for customer " + customerNumber, ex);
     }
  }

7
2017-10-05 12:58


Ursprung


Antworten:


Das Erstellen eines neuen Ausnahmetyps ist keine gute Option für a Allgemeines Methode wie diese, da der vorhandene Code nicht auf einen bestimmten Fehler reagieren kann. (Übersetzungsausnahmen an API-Grenzen können jedoch nützlich sein).

Es ist gefährlich, eine neue Ausnahme desselben Typs zu erstellen. Macht der CreateInstance Überladung Sie verwenden alle Felder aus dem kopieren innerException zu deiner neuen äußeren Ausnahme? Was ist, wenn ein Exception - Handler, der höher auf dem Stack liegt, vom Parsing des Message Eigentum? Was passiert, wenn der Ausnahmekonstruktor Nebenwirkungen hat?

IMHO, was du wirklich machst, ist Logging, und du wärst wahrscheinlich besser dran, Logging und einen Re-Throw zu machen.


4
2017-10-05 13:28



Alle Ausnahmen verfügen über eine Data-Eigenschaft, der Sie zusätzliche Daten hinzufügen können. Es ist nicht notwendig, eine neue Ausnahme zu erstellen. Fangen Sie einfach die bestehende Ausnahme und fügen Sie Ihre Informationen hinzu und wiederholen Sie dann die Ausnahme.

So bekommst du deinen Kuchen und isst ihn auch. :)

http://msdn.microsoft.com/en-us/library/system.exception_members(v=VS.90).aspx


12
2017-10-05 13:01



Ich denke, Sie sollten Ihren eigenen benutzerdefinierten Ausnahmetyp erstellen. Welche Art von Informationen werden Sie hinzufügen? Wie bekommt der Fänger der Ausnahme, die er erfährt, zusätzliche Informationen? Wenn Sie einen benutzerdefinierten Typ verwenden, verfügen sie über zusätzliche Eigenschaften / Methoden zum Anzeigen oder Aufrufen.


3
2017-10-05 13:01



Fange es überhaupt nicht und lass es einfach aufsteigen - es macht keinen Sinn, das Rad neu zu erfinden.

Ihre Methode ist nicht nur für jemanden, der reinkommt, nicht intuitiv, sondern Sie verlieren auch den ursprünglichen Stack-Trace von der ersten Ausnahme.


1
2017-10-05 13:00



Es kann in einigen Fällen sinnvoll sein. Wenn Sie MyClass.MyFunction die öffentliche "außerhalb" der Assembly betrachten, was dann passiert, ist eine Blackbox zum Aufrufen von Code. Es kann daher vernünftiger sein, dies als den Punkt zu haben, an dem die Ausnahme so weit geschah, wie der aufrufende Code geht, und der vernünftigste Typ der Ausnahme könnte der gleiche Typ sein wie der abgefangene.

Ich wäre jedoch vorsichtig. In den meisten Fällen, in denen dies passiert, hättest du entweder feststellen können, dass die Ausnahme passieren würde, und präventiv geworfen (wenn du würfelst, je früher, desto besser) oder die Ausnahme, die du fällst, ist nicht t wirklich der richtige Typ (wenn Ihr Code eine Datei nicht findet, die eine FileNotFoundException für Sie ist, aber wenn die Dateien ein Implementierungsdetail sind, dann ist es keine FileNotFoundException für den aufrufenden Code), sonst wird die ursprüngliche Ausnahme gemacht vollkommener Sinn und es sollte nur erlaubt sein, durch zu rufen oder zu wiederholen throw;.

Also nicht immer eine schlechte Idee, aber oft genug schlimm, dass es immer verdächtig ist, etwas zu sehen.


0
2017-10-05 13:15



IMHO, wäre es wahrscheinlich gut, ein paar benutzerdefinierte Ausnahmetypen, mit einer Hierarchie für Ausnahmen, die sagen: "Diese Operation fehlgeschlagen, aber der Systemzustand ist, als ob es nie versucht wurde", ein anderes für Ausnahmen, die sagen "Die Operation fehlgeschlagen , und der Systemstatus wurde gestört, aber wahrscheinlich kann er nicht abgewickelt werden "und ein anderer für" Der Vorgang ist fehlgeschlagen und das Abwickeln ist fehlgeschlagen; dem Systemstatus kann nicht vertraut werden. " In einigen Kontexten kann eine Ausnahmeklasse als eine andere erfasst und erneut ausgelöst werden (z. B. wenn eine Operation, die die Wiederherstellung des Systemzustands beenden sollte, fehlschlägt, auch wenn aus der Sicht dieser Operation nichts gestört wurde, das Wiederherstellen des Zustands fehlgeschlagen ist) Wenn eine Operation einen Systemzustand gestört hat, aber ein Catch-Handler den Zustand wiederhergestellt hat, könnte es umgekehrt als "Operation fehlgeschlagen, aber Systemzustand ist ungestört" erneut gestartet werden.

Ich mag die Idee nicht, zu versuchen, Ausnahme-Instanzen zu erstellen, die blind geworfene Ausnahme-Typen treffen, da die geworfenen Ausnahmen Felder enthalten können, die von Handlern erwartet werden. Ich bin nicht sicher, warum Microsoft Ausnahmen "fast" unveränderlich machte. Es wäre viel schöner, wenn Ausnahmen unabänderlich sein müssten und das Klonen mit jeder Semantik unterstützen würde, die unverrückbar vermittelt wird.


0
2017-10-05 14:26



Fangen Sie nur Ausnahmen ab, die Sie behandeln, zum Beispiel möchten Sie nicht, dass eine SqlException von Ihrer Datenschicht auf Ihre Business-Schicht geworfen wird (fangen Sie sie ab, versuchen Sie sie zu handhaben und werfen stattdessen eine DataLayerException oder etwas ähnliches).


0
2017-10-05 14:32