3 Stimmen

Auffangen von Ausnahmen

In dem folgenden Codestück wird die new Konstruktor ist dokumentiert, dass er sieben verschiedene Ausnahmetypen auslöst, darunter System.IO.PathTooLongException y System.ArgumentException , System.UnauthorizedAccessException y System.SecurityException :

try
{
    var fileInfo = new FileInfo(path);
}
catch ???

Ich versuche nur, sicherzustellen, dass die path ist tatsächlich ein zugänglicher Pfad und es passiert nichts Schlimmes, wenn ich versuche, eine Datei mit diesem path .

Also, die Frage:

Bücher und Kodierungsrichtlinien sagen mir, dass Ich sollte nicht catch (Exception) konstruieren, aber ich stehe vor folgender Situation: Ich kann 4 (von 7) Ausnahmetypen abfangen und behandeln und ihre Handhabung für alle Ausnahmetypen ist absolut gleich.

Wie sollte dies geschehen?


Ich kann mir auch die folgende Lösung vorstellen, aber sie sieht immer noch schlecht aus:

catch (Exception exception)
{
    Debug.Assert(exception is PathTooLongException || exception is ...);

    // (or maybe rethrow it further if there is a type mismatch)

    //... Handling code ...
}

0 Stimmen

Könnten Sie das genaue Nutzungsszenario beschreiben?

2voto

bryanmac Punkte 38186

Sie müssen nicht jede mögliche Ausnahme bei jeder Codezeile abfangen.

Fangen Sie stattdessen nur dann, wenn Sie den Kontext kennen und darauf vorbereitet sind, geeignete Maßnahmen zu ergreifen. Andernfalls lassen Sie es einfach aufsprudeln.

Das Auffangen von Ausnahmen (vor allem tief im Stack in allgemeinen Funktionen, wo man nicht genug Kontext hat, um sie zu behandeln) kann problematisch sein. Es führt manchmal dazu, dass Ausnahmen verschluckt und nicht angemessen behandelt werden. Behandeln Sie Ausnahmen, wenn Sie Kontext haben.

Bei dieser FileInfo-Ausnahme hängt es davon ab, wie tief sie im Stapel liegt. Wenn sie sich in einer Bibliothek befindet, in der sie über mehrere Pfade und Szenarien erreicht werden kann, sollten Sie sie nicht behandeln, was werden Sie an diesem Punkt tun? Wenn das auch der Fall ist und sie den ganzen Weg durch einen tiefen Stapel zu einer grafischen Benutzeroberfläche blubbert, die eine Operation durchführt, bei der Sie sie behandeln wollen, was werden Sie dann abfangen? Jede mögliche Ausnahme von jedem Codepfad auf seinem Ausführungspfad? Und wenn sich der Code ändert, werden Sie alle Pfade neu auswerten? In einem oberflächlichen Codepfad (Dateiinformationsdialog, der diese Methode aufruft) ist es ein einfacher Aufruf, aber selbst dann werden Sie es nicht anders behandeln - Sie werden einen Fehlerdialog oder eine Meldung im Panel anzeigen. Ausnahmetypen bieten die Möglichkeit, Folgendes zu behandeln anders . In beiden Fällen handhaben Sie Ausnahmen, also sage ich "bah hum bug" zu dieser Leitlinie.

Was ganz klar ist, ist, dass Sie nicht den Typ Exception . Das schließt die Fähigkeit, anders zu handeln, kurz.

Ein weiterer verwandter Beitrag:

Versuchen, Ausnahmen in C# zu verstehen

2voto

Jason Punkte 199

Sie können den Pfad auch zuerst mit File.Exists(path) oder Directory.Exists(path) testen

1voto

Alex Vaz Punkte 486

Ich möchte hier hinzufügen, dass die Behandlung von Ausnahmen in fast allen Java-Codes, die ich gesehen habe, einfach falsch ist. D.h. man bekommt sehr schwer zu debuggende Fehler für ignorierte Exceptions, oder, was genauso schlimm ist, man bekommt eine obskure Exception, die einem nichts sagt, weil man blind dem "catching(Exception) is bad" folgt und die Dinge sind einfach schlimmer.

Verstehen Sie zunächst, dass eine Ausnahme eine Möglichkeit ist, die Rückgabe von Fehlerinformationen über Codeschichten hinweg zu erleichtern. Fehler 1: Eine Schicht ist nicht nur ein Stackframe, eine Schicht ist Code, der eine genau definierte Verantwortung hat. Wenn Sie Schnittstellen und Impls einfach nur so kodiert haben, dann haben Sie Besseres zu tun.

Wenn die Ebenen gut gestaltet sind und bestimmte Zuständigkeiten haben, dann hat die Information des Fehlers eine andere Bedeutung, wenn sie auftaucht. <-das ist der Schlüssel zu dem, was zu tun ist, es gibt keine universelle Regel.

Das bedeutet also, dass Sie beim Auftreten einer Ausnahme 2 Möglichkeiten haben, aber Sie müssen wissen, wo in der Ebene Sie sich befinden:

A) Wenn Sie sich in der Mitte einer Schicht befinden und Sie nur eine interne, normalerweise private Hilfsfunktion sind und etwas schief geht: DONT WORRY, lassen Sie den Aufrufer die Ausnahme erhalten. Das ist völlig in Ordnung, denn Sie haben keinen geschäftlichen Kontext und 1) Sie ignorieren den Fehler nicht und 2) Der Aufrufer ist Teil Ihrer Schicht und hätte wissen müssen, dass so etwas passieren kann, aber Sie haben jetzt vielleicht nicht den Kontext, um es unten zu behandeln.

oder ...

B) Sie sind die obere Grenze der Schicht, die Fassade zu den Interna. Wenn dann eine Ausnahme auftritt, ist die Standardeinstellung CATCH ALL und verhindert, dass bestimmte Ausnahmen in die obere Schicht gelangen, was für den Aufrufer keinen Sinn macht, oder noch schlimmer, Sie könnten sich ändern und der Aufrufer hat eine Abhängigkeit zu einem Implementierungsdetail und beide brechen.

Die Stärke einer Anwendung ist der Entkopplungsgrad zwischen den Schichten. Hier wird in der Regel alles gestoppt und der Fehler mit einer generischen Ausnahme zurückgeworfen, die die Informationen in einen aussagekräftigeren Fehler für die obere Schicht übersetzt.

REGEL: Alle Eingangspunkte zu einer Schicht müssen mit CATCH ALL geschützt und alle Fehler übersetzt oder behandelt werden. Nun kommt diese "Behandlung" nur in 1% der Fälle vor, meistens muss (oder kann) man den Fehler nur in einer korrekten Abstraktion zurückgeben.

Nein, ich bin sicher, das ist sehr schwer zu verstehen. echtes Beispiel ->

Ich habe ein Paket, das einige Simulationen durchführt. Diese Simulationen sind in Text-Skripten. Es gibt ein Paket, das diese Skripte kompiliert und es gibt ein generisches utils-Paket, das nur Textdateien und natürlich die Basis-Java-RTL liest. Die UML-Abhängigkeit ist->

Simulator->Compiler->utilsTextLoader->Java-Datei

1) Wenn etwas im Utilities-Loader innerhalb eines Private kaputt geht und ich eine FileNotFound, Permissions oder was auch immer bekomme, dann lass es einfach durchgehen. Es gibt nichts anderes, was Sie tun können.

2) An der Grenze, in der Funktion utilsTextLoader, die zunächst aufgerufen wird, folgen Sie der obigen Regel und CATCH_ALL. Dem Compiler ist es egal, was passiert, er muss nur wissen, ob die Datei geladen wurde oder nicht. In der Catch-Funktion werfen Sie also eine neue Exception und übersetzen die FileNotFound oder was auch immer in "Could not read file XXXX".

3) Der Compiler weiß nun, dass die Quelle nicht geladen wurde. Das ist ALLES, was er wissen muss. Wenn ich also später utilsTestLoader ändere, um vom Netzwerk zu laden, wird sich der Compiler nicht ändern. Wenn Sie FileNotFound loslassen und später ändern, wird der Compiler umsonst beeinflusst.

4) Der Zyklus wiederholt sich: Die eigentliche Funktion, die die untere Schicht für die Datei aufgerufen hat, tut nichts, wenn sie die Ausnahme erhält. Sie lässt sie also nach oben gehen.

5) Wenn die Ausnahme die Schicht zwischen Simulator und Compiler erreicht, wird der Compiler wieder CATCHES_ALL, wobei er alle Details ausblendet und nur einen spezifischeren Fehler ausgibt: "Could not compile script XXX"

6) Zum Schluss wiederholen Sie den Zyklus ein weiteres Mal, die Simulatorfunktion, die den Compiler aufgerufen hat, lässt einfach los.

7) Die letzte Grenze liegt beim Nutzer. Der Benutzer ist ein LAYER und alles gilt. Die wichtigsten hat eine versuchen, dass catches_ALL und schließlich macht nur ein schönes Dialogfeld oder Seite und "wirft" einen übersetzten Fehler an den Benutzer.

So sieht der Benutzer.


Simulator: Fataler Fehler: Simulator konnte nicht gestartet werden

-Compiler: Das Skript FOO1 konnte nicht kompiliert werden.

-TextLoader: Konnte Datei foo1.scp nicht lesen

---trl: FileNotFound


Vergleichen mit:

a) Compiler: NullPointer Exception <-Häufiger Fall und eine verlorene Nacht beim Debuggen eines Dateinamen-Tippfehlers

b) Lader: Datei nicht gefunden <- Habe ich schon erwähnt, dass Loader hunderte von Skripten lädt?

oder

c) Es passiert nichts, weil alles ignoriert wurde!!!

Dies setzt natürlich voraus, dass Sie bei jedem Rückwurf nicht vergessen haben, die Ausnahmeursache zu setzen.

Nun meine 2cts. Diese einfachen Regeln haben mir schon oft das Leben gerettet...

-Ale

0voto

Hugo Punkte 710

Sie könnten etwa so vorgehen:

try
{
    var fileInfo = new FileInfo(path);
}
catch (System.IO.PathTooLongException ex)
{
    handleError(ex);
}
catch (System.ArgumentException ex)
{
   handleError(ex);
}
catch (System.UnauthorizedAccessException ex)
{
}
catch (System.SecurityException ex)
{
   handleError(ex);
}

public void handleError(Exception ex)
{
    //do some stuff
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X