Werfen/tun-nicht-eine Ausnahme basierend auf einem parameter - warum ist das nicht eine gute Idee?

StackOverflow https://stackoverflow.com/questions/624647

Frage

Ich war zu Graben um in den MSDN-und gefunden in diesem Artikel die hatte einen interessanten Tipp: Nicht öffentliche Mitglieder, die entweder werfen oder nicht werfen Ausnahmen basierend auf einige option.

Zum Beispiel:

Uri ParseUri(string uriValue, bool throwOnError)

Jetzt kann ich natürlich sehen, dass in 99% der Fälle das würde schrecklich sein, aber ist Ihre gelegentliche Verwendung gerechtfertigt?

Einem Fall, den ich gesehen habe Sie verwendet, ist mit einem "AllowEmpty" - parameter beim Zugriff auf Daten in der Datenbank oder einer Konfigurationsdatei.Zum Beispiel:

object LoadConfigSetting(string key, bool allowEmpty);

In diesem Fall ist die alternative wäre auf null zurück.Aber dann wird der aufrufende code wäre übersät mit null-Referenzen überprüfen.(Und die Methode würde auch ausschließen, dass die Fähigkeit, wirklich null als eine speziell konfigurierbaren Wert, wenn Sie so geneigt sind).

Was sind Ihre Gedanken?Warum wäre das ein großes problem?

War es hilfreich?

Lösung

Ich denke, es ist definitiv eine schlechte Idee, einen Wurf / nein Wurf-Entscheidung aus basierte einen boolean zu haben. Und zwar, weil es die Entwickler an einem Stück Code suchen erfordert eine funktionale Kenntnisse über die API haben, um zu bestimmen, was die Booleschen Mittel. Das ist schlecht auf seine eigenen, aber wenn es die zugrunde liegenden Fehler ändert Handhabung kann es sehr einfach für Entwickler, Fehler zu machen, während Code zu lesen.

Es wäre viel besser und besser lesbar 2 APIs in diesem Fall zu haben.

Uri ParseUriOrThrow(string value);

bool TryParseUri(string value, out Uri uri);

In diesem Fall ist es 100% klar, was dieser APIs tun.

Artikel darüber, warum booleans sind schlecht als Parameter: http : //blogs.msdn.com/jaredpar/archive/2007/01/23/boolean-parameters.aspx

Andere Tipps

Es ist in der Regel am besten einen Fehlerbehandlungsmechanismus zu wählen und bleiben Sie dabei konsequent. Unter Berücksichtigung dieser Art von Flip-Flop-Code kann das Leben der Entwickler nicht wirklich verbessern.

Im obigen Beispiel, was passiert, wenn das Parsen ausfällt und throwOnError ist falsch? Nun muss der Benutzer, wenn NULL zu erraten, wenn das Gehen zu zurückgegeben, oder Gott weiß ...

True gibt es eine anhaltende Debatte zwischen Ausnahmen und Rückgabewerte als die bessere Fehlerbehandlung Methode, aber ich bin ziemlich sicher, es gibt einen Konsens, konsequent zu sein und das Festhalten mit dem, was Sie sich entscheiden. Die API kann nicht seine Nutzer überraschen und Fehlerbehandlung soll einen Teil der Schnittstelle und wird so klar definiert als die Schnittstelle sein.

Es ist eine Art böse von einem Standpunkt Lesbarkeit. Entwickler neigen dazu, jede Methode zu erwarten, eine Ausnahme zu werfen, und wenn sie die Ausnahme ignorieren wollen, werden sie es selbst fangen. Mit dem ‚boolean Flag‘ -Ansatz, muss jede einzelne Methode dieser Ausnahme hemmende semantische implementieren.

Aber ich denke, der MSDN-Artikel streng Flags ‚throwOnError‘ bezieht. In diesen Fällen entweder wird der Fehler in der Methode selbst ignoriert (schlecht, wie es versteckt ist) oder irgendeine Art von null / Fehlerobjekt wird (schlecht zurückgegeben, weil Sie nicht Ausnahmen mit den Fehler zu behandeln, die inkonsistent ist und selbst Fehler -prone).

Während Ihr Beispiel scheint mir in Ordnung. Eine Ausnahme gibt einen Fehler des Verfahrens seine Aufgabe zu erfüllen - es gibt keinen Rückgabewert. Doch die ‚allowEmpty‘ Flag die Semantik ändert des Verfahrens - so was wäre eine Ausnahme ( ‚Leerwert‘) haben wird nun erwartet und legal. Plus, wenn Sie Had eine Ausnahme geworfen, würden Sie nicht einfach in der Lage sein, die Konfigurationsdaten zurückzukehren. So scheint es OK in diesem Fall.

In einer öffentlichen API ist es wirklich eine schlechte Idee, zwei Möglichkeiten zu haben, um einen fehlerhaften Zustand zu überprüfen, denn dann wird es nicht klar, was passieren wird, wenn der Fehler auftritt. Nur durch Blick auf den Code wird nicht helfen. Sie müssen die Semantik der Flag-Parameter verstehen (und nichts verhindert, dass es zu sein Ausdruck).

Wenn für null Überprüfung nicht möglich ist, und wenn ich von diesem spezifischen Ausfall wiederherstellen muß, ziehe ich eine spezifische Ausnahme zu erstellen, so dass ich es später fangen und sie entsprechend behandeln. In jedem anderen Fall werfe ich eine allgemeine Ausnahme.

Ein weiteres Beispiel in Einklang mit diesem von TryParse Methoden auf einige der Werttypen festgelegt werden konnte

bool DateTime.TryParse(string text, out DateTime)

einen donTThrowException Parameter Mit Niederlagen des ganzen Sinne der Ausnahme (in jeder Sprache). Wenn der anruf Code haben will:

public static void Main()
{
        FileStream myFile = File.Open("NonExistent.txt", FileMode.Open, FileAccess.Read);
}

Sie sind willkommen zu (C # auch geprüfte Ausnahmen haben nicht). In Java würde die gleiche Sache mit erreicht werden:

public static void main(String[] args) throws FileNotFoundException
{
        FileInputStream fs = new FileInputStream("NonExistent.txt");
}

So oder so, ist es die Aufgabe des Anrufers zu entscheiden, wie (oder nicht), um die Ausnahme zu behandeln, nicht die Angerufenen.

In dem zu Artikel verknüpft ist ein Hinweis, dass Ausnahmen sollten nicht für Ablaufsteuerung verwendet werden -, die in dem Beispiel questsions impliziert zu sein scheint. Ausnahmen sollten Methode Ebene Versagen widerspiegeln. Um eine Signatur, die es OK ist ein Fehler zu werfen scheint, wie das Design ist nicht durchdacht.

Jeffrey Richters Buch CLR via C # weist darauf hin, - „Sie eine Ausnahme auslösen sollen, wenn das Verfahren nicht seine Aufgabe durch seinen Namen, wie angegeben durchführen kann“.

Sein Buch wies auch einen sehr häufigen Fehler aus. Menschen neigen dazu, Code zu schreiben, alles (seine Worte „Ein allgegenwärtiger Fehler von Entwicklern zu fangen, die nicht auf dem richtigen Gebrauch von Ausnahmen richtig ausgebildet worden ist in der Regel zu oft catch-Blöcke zu verwenden, und nicht richtig. Wenn Sie eine Ausnahme zu fangen, die besagen, dass Sie Sie diese Ausnahme, verstehen Sie, warum es aufgetreten ist, und Sie wissen, wie sie damit umgehen. ")

Das hat mich für Ausnahmen versuchen, Code gemacht, dass ich erwarten kann und in meiner Logik umgehen kann sonst sollte es ein Fehler sein.

Ihre Argumente Validieren und die Ausnahmen zu verhindern, und nur fangen, was Sie behandeln können.

Ich möchte betonen, dass es ist oft nützlich, einen parameter, der angibt, ob ein Ausfall zu einer Ausnahme führen, oder einfach wieder ein Fehler angezeigt, da eine solche können die Parameter leicht bestanden aus einer äußeren routine, um eine innere.Betrachten Sie etwas wie:

Byte[] ReadPacket(bool DontThrowIfNone) // Dokumentiert als null zurückgeben, wenn keine { int len = ReadByte(DontThrowIfNone);// Dokumentiert, wie die Rückkehr -1, wenn nichts if (len

Wenn etwas wie eine TimeoutException beim Lesen der Daten sollte dazu führen, dass eine Ausnahme, die diese Ausnahme geworfen werden sollte innerhalb der ReadByte() oder ReadMultiBytesbytes().Wenn jedoch so ein Mangel an Daten sollte als normal angesehen werden, dann ist die ReadByte() oder ReadMultiBytesbytes() routine sollte nicht eine Ausnahme.Wenn man einfach benutzt das tun/versuchen Sie, Muster, die ReadPacket und TryReadPacket Routinen, müssten fast identischen code, aber mit der Verwendung Lesen* Methoden und der andere mit TryRead* Methoden.Eklig.

Kann es besser sein, auf eine Aufzählung anstatt einen booleschen Wert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top