Ich bin auf diese MSDN-Seite gestoßen , auf der es heißt:
Werfen Sie Exception , SystemException , NullReferenceException oder IndexOutOfRangeException nicht absichtlich aus Ihrem eigenen Quellcode.
Leider macht es sich nicht die Mühe zu erklären, warum. Ich kann die Gründe erraten, aber ich hoffe, dass jemand, der zu diesem Thema maßgeblicher ist, seine Einsicht bietet.
Die ersten beiden machen einen offensichtlichen Sinn, aber die beiden letzteren scheinen diejenigen zu sein, die Sie beschäftigen möchten (und tatsächlich habe ich).
Sind dies die einzigen Ausnahmen, die man vermeiden sollte? Wenn es andere gibt, was sind sie und warum sollten auch sie vermieden werden?
c#
exception-handling
DonBoitnott
quelle
quelle
NullArgumentException
manche Leute beide verwirren könnten.ApplicationException
Antworten:
Exception
ist der Basistyp für alle Ausnahmen und als solcher furchtbar unspezifisch. Sie sollten diese Ausnahme niemals auslösen, da sie einfach keine nützlichen Informationen enthält. Das Aufrufen des Code-Catching für Ausnahmen konnte die absichtlich ausgelöste Ausnahme (aus Ihrer Logik) nicht von anderen Systemausnahmen unterscheiden, die völlig unerwünscht sind und auf echte Fehler hinweisen.Der gleiche Grund gilt auch für
SystemException
. Wenn Sie sich die Liste der abgeleiteten Typen ansehen, sehen Sie eine Vielzahl anderer Ausnahmen mit sehr unterschiedlicher Semantik.NullReferenceException
undIndexOutOfRangeException
sind von einer anderen Art. Nun, dies sind sehr spezifische Ausnahmen, daher könnte es in Ordnung sein , sie zu werfen . Sie werden diese jedoch immer noch nicht werfen wollen, da sie normalerweise bedeuten, dass Ihre Logik einige tatsächliche Fehler enthält. Die Nullreferenzausnahme bedeutet beispielsweise, dass Sie versuchen, auf ein Mitglied eines Objekts zuzugreifennull
. Wenn dies in Ihrem Code möglich ist, sollten Sienull
stattdessen immer explizit nach einer nützlicheren Ausnahme suchen und diese auslösen (zum BeispielArgumentNullException
). In ähnlicher Weise trittIndexOutOfRangeException
s auf, wenn Sie auf einen ungültigen Index zugreifen (für Arrays - nicht für Listen). Sie sollten immer sicherstellen, dass Sie dies überhaupt nicht tun, und zuerst die Grenzen eines Arrays überprüfen.Es gibt einige andere Ausnahmen wie diese beiden, zum Beispiel
InvalidCastException
oderDivideByZeroException
, die für bestimmte Fehler in Ihrem Code ausgelöst werden und normalerweise bedeuten, dass Sie etwas falsch machen oder nicht zuerst nach ungültigen Werten suchen. Indem Sie sie wissentlich aus Ihrem Code entfernen, erschweren Sie es dem aufrufenden Code nur, festzustellen, ob sie aufgrund eines Fehlers im Code ausgelöst wurden, oder nur, weil Sie beschlossen haben, sie für etwas in Ihrer Implementierung wiederzuverwenden.Natürlich gibt es einige Ausnahmen (hah) von diesen Regeln. Wenn Sie etwas erstellen, das eine Ausnahme verursachen kann, die genau mit einer vorhandenen übereinstimmt, können Sie diese verwenden, insbesondere wenn Sie versuchen, einem integrierten Verhalten zu entsprechen. Stellen Sie einfach sicher, dass Sie dann einen ganz bestimmten Ausnahmetyp auswählen.
Im Allgemeinen sollten Sie jedoch immer in Betracht ziehen, eigene Ausnahmetypen für bestimmte erwartete Ausnahmen zu erstellen, es sei denn, Sie finden eine (bestimmte) Ausnahme, die Ihren Anforderungen entspricht. Insbesondere wenn Sie Bibliothekscode schreiben, kann dies sehr nützlich sein, um die Ausnahmequellen zu trennen.
quelle
IList
Implementierung schreiben , liegt es nicht in Ihrer Macht, die angeforderten Indizes zu beeinflussen. Es ist der logische Fehler des Aufrufers, wenn ein Index ungültig ist, und Sie können sie nur informieren dieses logischen Fehlers durch Auslösen einer entsprechenden Ausnahme. Warum ist dasIndexOutOfRangeException
nicht angebracht?IList
, werfen Sie ein,ArgumentOutOfRangeException
wie in der Schnittstellendokumentation vorgeschlagen .IndexOutOfRangeException
ist für Arrays, und soweit ich weiß, können Sie Arrays nicht erneut implementieren.NullReferenceException
wird normalerweise intern als Sonderfall einesAccessViolationException
(IIRC der Test ist so etwas wiecmp [addr], addr
, dh es versucht, den Zeiger zu dereferenzieren und wenn es mit einer Zugriffsverletzung fehlschlägt, behandelt es den Unterschied zwischen NRE und AVE im resultierenden Interrupt-Handler). Abgesehen von semantischen Gründen gibt es also auch Betrug. Dies kann Sie auch davon abhalten,null
manuell zu suchen, wenn dies nicht hilfreich ist. Wenn Sie trotzdem eine NRE auslösen möchten, lassen Sie .NET dies tun.Ich vermute, die Absicht mit den letzten 2 ist es, Verwechslungen mit eingebauten Ausnahmen zu verhindern, die eine erwartete Bedeutung haben. Ich bin jedoch der Meinung, dass, wenn Sie die genaue Absicht der Ausnahme beibehalten : es die richtige ist
throw
. Wenn Sie beispielsweise eine benutzerdefinierte Sammlung schreiben, erscheint die Verwendung völlig vernünftigIndexOutOfRangeException
- klarer und spezifischer, IMO, alsArgumentOutOfRangeException
. Und während SieList<T>
sich für Letzteres entscheiden könnten, gibt es in der BCL mindestens 41 Stellen (mit freundlicher Genehmigung des Reflektors) (ohne Arrays), die maßgeschneidert sindIndexOutOfRangeException
- keine davon ist "niedrig" genug, um eine besondere Ausnahme zu verdienen. Also ja, ich denke, Sie können zu Recht argumentieren, dass diese Richtlinie albern ist. Gleichfalls,NullReferenceException
ist ein bisschen nützlich in Erweiterungsmethoden - wenn Sie die Semantik beibehalten möchten, dass:wirft ein
NullReferenceException
wannobj
istnull
.quelle
SomeMethod()
kein Mitgliederzugriff erforderlich ist, ist es falsch, ihn zu erzwingen. Ebenso: Nehmen Sie diesen Punkt mit den 41 Stellen in der BCL, die benutzerdefinierte erstellenIndexOutOfRangeException
, und den 16 Stellen, die benutzerdefinierte erstellenNullReferenceException
ArgumentNullException
anstelle von a werfen sollteNullReferenceException
. Selbst wenn der syntaktische Zucker aus Erweiterungsmethoden dieselbe Syntax wie der normale Mitgliederzugriff zulässt, funktioniert er dennoch sehr unterschiedlich. Und ein NRE von zu bekommenMyStaticHelpers.SomeMethod(obj)
wäre einfach falsch.Wie Sie bereits erwähnt haben, listet Microsoft im Artikel Erstellen und Auslösen von Ausnahmen (C # -Programmierhandbuch) unter dem Thema Zu vermeidende Dinge beim Auslösen von Ausnahmen tatsächlich
System.IndexOutOfRangeException
einen Ausnahmetyp auf, der nicht absichtlich aus Ihrem eigenen Quellcode ausgelöst werden sollte.Im Gegensatz dazu scheint Microsoft im Artikelwurf (C # -Referenz) gegen seine eigenen Richtlinien zu verstoßen. Hier ist eine Methode, die Microsoft in sein Beispiel aufgenommen hat:
Microsoft selbst ist also nicht konsistent, da es das Werfen
IndexOutOfRangeException
in seiner Dokumentation fürthrow
!Dies führt mich zu glauben , dass zumindest für den Fall
IndexOutOfRangeException
, kann es vorkommen , dass dieser Ausnahme - Typ kann durch den Programmierer geworfen werden und eine akzeptable Praxis berücksichtigt werden.quelle
Als ich Ihre Frage las, fragte ich mich, unter welchen Bedingungen man die Ausnahmetypen auslösen möchte
NullReferenceException
,InvalidCastException
oderArgumentOutOfRangeException
.Wenn ich auf einen dieser Ausnahmetypen stoße, bin ich (der Entwickler) meiner Meinung nach besorgt über die Warnung in dem Sinne, dass der Compiler mit mir spricht. Wenn Sie (der Entwickler) solche Ausnahmetypen auslösen können, entspricht dies (dem Compiler) dem Verkauf der Verantwortung. Dies legt beispielsweise nahe, dass der Compiler dem Entwickler nun erlauben sollte, zu entscheiden, ob es sich um ein Objekt handelt
null
. Aber eine solche Entscheidung zu treffen, sollte wirklich die Aufgabe des Compilers sein.PS: Seit 2003 entwickle ich meine eigenen Ausnahmen, damit ich sie nach Belieben werfen kann. Ich denke, dies wird als bewährte Methode angesehen.
quelle
Die Diskussion über
NullReferenceException
undIndexOutOfBoundsException
beiseite legen:Was über den Fang und werfen
System.Exception
. Ich habe diese Art von Ausnahme oft in meinen Code geworfen und wurde nie davon verarscht. Ebenso fange ich sehr oft den unspezifischenException
Typ und es hat auch ziemlich gut für mich funktioniert. Warum ist das so?Normalerweise argumentieren Benutzer, dass sie in der Lage sein sollten, Fehlerursachen zu unterscheiden. Nach meiner Erfahrung gibt es nur sehr wenige Situationen, in denen Sie verschiedene Ausnahmetypen unterschiedlich behandeln möchten. In den Fällen, in denen Benutzer Fehler programmgesteuert behandeln sollen, sollten Sie einen spezifischeren Ausnahmetyp auslösen. In anderen Fällen bin ich von der allgemeinen Best-Practice-Richtlinie nicht überzeugt.
In Bezug auf das Werfen
Exception
sehe ich keinen Grund, dies in allen Fällen zu verbieten.BEARBEITEN: auch von der MSDN-Seite:
Das Übertreiben von catch-Klauseln mit individueller Logik für verschiedene Ausnahmetypen ist ebenfalls keine bewährte Methode.
quelle