Dies ist eine allgemeine Entwurfsfrage, aber ich konzentriere mich auf C # und .NET, da dies die Sprachen sind, mit denen ich gerade arbeite.
Sollte ich meine eigenen, neuen Ausnahmeklassen erstellen oder vorhandene Framework-Ausnahmen für etwas andere Zwecke kooptieren?
Ich benötige beispielsweise eine Ausnahme, die angibt, dass ein Mitglied (z. B. ein Typ) erwartet wurde, aber beim Lesen einer Assembly mit nicht gefunden wurde Mono.Cecil
. Die Basisklassenbibliothek definiert die Ausnahme MissingMemberException
, die genau das zu kommunizieren scheint, was ich will, aber die Beschreibung sagt:
Die Ausnahme, die ausgelöst wird, wenn versucht wird, dynamisch auf ein nicht vorhandenes Klassenmitglied zuzugreifen.
Das passt nicht genau, weil ich nicht dynamisch auf das Mitglied zugreife, sondern passiv mit der Assembly arbeite.
quelle
Antworten:
Allgemein
Das Unterklassifizieren von Ausnahmen ist eine gute Idee, um die Ausnahmen in die Familien oder Gruppierungen zu gruppieren, zu denen sie gehören. Außerdem kann Client-Code Ausnahmen behandeln, die auf bestimmten Fehlern oder allgemeiner basieren. Normalerweise teile ich den Baum irgendwo in der Nähe der Wurzel zwischen logischen und Laufzeitfehlern auf (z. B. in C ++ das
std::runtime_error
vs.std::logic_error
).Es ist auch eine gute Idee, zwischen den Systemausnahmen und den Ausnahmen Ihrer Anwendung unterscheiden zu können. Es wäre seltsam, wenn der Client-Code nach einem Systemfehler Ausschau hält, aber den logischen Fehler Ihres (über eine Basisklasse) Codes abfängt.
In diesem Fall und C #
C # hat eine reichhaltige und große Ausnahmehierarchie - ich würde nicht versuchen, eine Basisklasse zu tief darin aufzunehmen. Wenn Sie Ihrem Beispiel folgen, scheint es, als würden Sie einen logischen Fehler (oder zumindest einen Anwendungsfehler) auslösen, sodass die Basisklasse oder auch nur diese Ausnahme auf einen Systemfehler hinweisen würde. Die genaue Ausnahme kann diskutiert werden, aber ich denke in diesem Fall ist es keine gute Wahl.
Hierarchie
Ich würde eine Hierarchie erstellen, die es Ihnen ermöglicht, zwischen System- und Anwendungsfehlern und dann weiter zwischen Laufzeit- und logischen Fehlern zu unterscheiden. Haben Sie keine Angst davor, innere Ausnahmen zu verwenden - fangen Sie den Systemfehler ab und wickeln Sie ihn in etwas Bedeutenderes ein, wenn man bedenkt, in welchen Kontext er geworfen wird. Gehen Sie nicht über Bord, sondern konzentrieren Sie sich auf die wichtigsten Ausnahmen. Mit Ausnahmen können eindeutige Textbeschreibungen verknüpft sein. Verwenden Sie diese, um dem Benutzer noch mehr Details oder Hinweise zu geben, wie das Problem behoben werden kann.
quelle
Die Antwort lautet natürlich "es kommt darauf an", aber angesichts Ihres Anwendungsfalls würde ich nein sagen. Hier ist der Grund:
C # ist eine wunderbare - Kratzer, die beste - objektorientierte Sprache. Es ist in der Tat so gut, dass ich manchmal versucht werde, eine fanatisch puristische Vision von dem umzusetzen, was als einfaches Projekt begann. Das passiert mir beim Schreiben von JavaScript, Objective-C oder PHP-Code nicht so sehr.
Wenn ich in diesen "Modus", diese Art von Lähmung, gerate, kann eines der Symptome eine Besessenheit von Ausnahmebehandlung und Generika und Metaprogrammierung sein. Manchmal alle drei zusammen. Es ist weitaus wahrscheinlicher, dass ich ein Problem habe, wenn ich an etwas Neuem, relativ Unbekanntem oder mit schlechten Spezifikationen und Zielen arbeite. Anstatt mich in den Implementierungsdetails festzumachen , denke ich, warum sollte ich versuchen, etwas zu schaffen, das die meisten Szenarien berücksichtigt, die ich vernünftigerweise vorwegnehme? Wenn ich mich dann um die Details kümmere, wird der Grundstein gelegt und ich werde ein paar stumpfe kleine Methoden schreiben und so weiter. Vielleicht wird jemand anderes am UI-Code arbeiten, ich werde ihnen nur diese netten Dienste und diese Verträge anbieten ...
Das ist mir leider noch nicht passiert. Was dazu neigt, ist, dass ich diesen Weg beschreite und an "Infrastruktur" arbeite - Dinge wie:
Castle.Windsor
Interceptors
und Umschließen von AufrufenIRepository
,IUnitOfWork
,IDomainService
,ICrossCuttingValidation
, usw.IFrameworkException
)Wenn Sie sich nicht sicher sind, ob die Beschreibung einer Ausnahme genau genug für Ihren Geschmack ist, verweigern Sie wirklich die Implementierung einer anderen wichtigen Funktion. Die Art der Ausnahme ist ebenfalls aussagekräftig - es handelt sich nicht um eine ereignisgesteuerte Ausnahme, sie tritt offensichtlich weit entfernt von einer Eingabemethode (wie einer Benutzeroberfläche oder einer Pipe oder etwas anderem) auf und ist wahrscheinlich deterministischer Natur - wie in, können Sie nicht Vorhersagen, was ein Benutzer eingeben wird, aber Sie können vorhersagen, welche Baugruppe Sie laden möchten oder was nicht.
Übrigens, wenn Sie die Beschreibung so sehr stört, können Sie dann keine Erweiterungsmethode schreiben, um sie im entsprechenden Bereich zu überschreiben?
Das ist wirklich nur meine Art, meine eigene Überabstraktions- und Analyse-Lähmung auf Sie zu projizieren, aber ich denke, es könnte angemessen sein. Ich würde sagen, um auf der sicheren Seite zu bleiben, nur eine Unterklasse und
Exception
wann:Exception
Unterklassen noch nicht gut abgedecktquelle
Aus meiner Sicht sind benutzerdefinierte Ausnahmen nur in zwei Fällen sinnvoll:
1) Sie entwickeln eine API
2) Sie verwenden es in Ihrem Code, um einen Fehler zu beheben.
In jedem anderen Szenario sollten integrierte Ausnahmen ausreichend sein.
In Ihrem Fall könnten Sie InvalidArgumentException verwenden
quelle