Exception Flashcards
Exceptions
Exceptions (Ausnahmen) treten auf, wenn das Programm zur Laufzeit
versucht eine unzulässige Operation durchzuführen.
› Das können sehr unterschiedliche Operationen sein, z. B.:
› Eine benötigte Datei ist nicht vorhanden
› Fehlerhafte Anmeldung an einem Server oder Abbruch von
Netzwerkverbindung
› Eine Objektvariable ist nicht initialisiert
› Es wird versucht durch 0 zu teilen
› In diesen Fällen löst die Laufzeitumgebung eine Ausnahme aus und „wirft“
(throw) ein Exception-Objekt, das an einer anderen Stelle im Code„ gefangen“ (catch) und behandelt werden kann.
Grundlagen Exceptions
Wenn eine Exception geworfen wird, wird zunächst geprüft, ob die Exception
innerhalb der betroffenen Methode gefangen wird.
› Ist dies der Fall, kann sie dort behandelt werden und das Problem ist
behoben.
› Ist dies nicht der Fall, wird die Exception an die aufrufende Methode
weitergegeben und dort erfolgt wieder eine Prüfung.
›Dies geht so weiter, bis die Exception in der Main-Methode angekommen ist
(Call-Stack).
› Wird die Exception dort ebenfalls nicht gefangen, wird das Programm
abgebrochen und eine Fehlermeldung ausgegeben.
Grundlagen Exceptions
Entlang der Aufrufersequenz haben die beteiligten Methoden jeweils folgende
Reaktionsmöglichkeiten:
das Ausnahmeobjekt abfangen und das Problem behandeln
Die Laufzeitumgebung überprüft, ob die betroffene Methode geeigneten Code zur Behandlung
des Ausnahmeobjekts (einen sogenannten Exception-Handler) enthält. Nach der
Ausnahmebehandlung kann die Methode …
entweder ihre Tätigkeit mit einem angepassten Handlungsplan fortsetzen
oder ihrerseits ein Ausnahmeobjekt werfen (entweder das ursprüngliche oder ein
informativeres) und somit die Kontrolle an ihren Aufrufer zurückgeben.
das Ausnahmeobjekt ignorieren
In diesem Fall besitzt eine Methode keinen zum Ausnahmeobjekt passenden Exception-
Handler. Die Methode wird beendet, und das Ausnahmeobjekt wird dem Vorgänger in der
Aufrufersequenz überlassen.
Exceptions werfen (throw)
Exceptions können nicht nur
von der Laufzeitumgebung
geworfen werden.
›Der Anwendungscode kann
selbst Exceptions werfen.
›Dies geschieht mit dem
Schlüsselwort throw.
› Das kann am Beginn einer
Methode sinnvoll sein, um die
Parameter zu prüfen.
Exceptions werfen (throw)
Wenn eine Exception geworfen wird, wird ein passender try-catch Block zur
Ausnahmebehandlung entlang des Call Stack gesucht. Wird die Exception bis
zur Main Methode nicht behandelt, wird der Prozess durch die Ausnahme
beendet.
› Als Call Stack bezeichnet man die Aufrufreihenfolge der Methoden, in der die
aktuelle Anweisung aufgeführt wird.
› Beim Werfen der Exception im vorherigen Beispiel befinden sich die Methoden
in folgender Weise auf dem Call Stack:
› * FunktionB
› * FunktionA
› * Main
Exceptions werfen (throw)
Durch try-catch Blöcke können Exceptions behandelt und damit ein Absturz
verhindert werden.
› Dabei ist dieses Konstrukt so zu verstehen, dass Exceptions, die innerhalb
eines try Blocks geworfen werden, den Kontrollfluss so ändern, das als nächstes
die Anweisungen im catch Block ausgeführt werden, der sich entlang des Call
Stacks am nächsten zur ausgelösten Exception befindet und zum deren Typ
passt.
Exceptions abfangen
C# erlaubt folgende Varianten der try - Anweisung:
try-catch - Anweisung
try-finally - Anweisung
try-catch-finally – Anweisung
Ein try-, catch- oder finally-Block benötigt auch dann ein einrahmendes Paar geschweifter
Klammern, wenn nur eine Anweisung enthalten ist.
Ausnahmebehandlung mit catch-Block
Ein catch-Block wird auch als Exception-Handler bezeichnet und besitzt im Kopfbereich eine
einelementige Parameterliste. Anders als bei einer Methode kann sich die Parameterliste eines
catch-Blocks auf die Typangabe beschränken oder ganz fehlen.
›Tritt im try-Block eine Ausnahme auf, wird seine Ausführung abgebrochen. Anschließend sucht
das Laufzeitsystem nach einem catch-Block, dessen Parameter den Typ der zu behandelnden
Ausnahme oder einen Basistyp besitzt und führt dann den zugehörigen Anweisungsblock aus.
›Weil die Liste der catch-Blöcke von oben nach unten durchsucht wird, müssen
Ausnahmebasisklassen stets unter abgeleiteten Klassen stehen.
Exceptions abfangen
Exceptions können (und sollten) im Code gefangen und behandelt werden.
Exceptions, die innerhalb eines try-Blocks geworfen werden, ändern den
Kontrollfluss so, das als nächstes die Anweisungen im catch Block ausgeführt
werden, der sich entlang des Call Stacks am nächsten zur ausgelösten
Exception befindet und zum deren Typ passt.
Exceptionklassen
Jedes Exception-Objekt, das von der Laufzeitumgebung im Fehlerfall erzeugt
wird, hat eine Reihe von Properties.
› Die wichtigsten davon sind:
› Message:
› String mit der Beschreibung der Ausnahme
› StackTrace:
› String mit der Aufruf-Reihenfolge aller Methoden bis zur Ausnahme
› InnerException:
› Exception, deren Behandlung die aktuelle Exception ausgelöst hat
› Data:
› Dictionary mit Zusatzinformationen zur Ausnahme
Eigene Exceptionklassen
Folgende Punkte sind zu beachten:
› Die eigene Klasse muss direkt oder indirekt von System.Exception ableiten.
›Ausnahmen sollten keine Methoden enthalten, die Logik ausführen, die für das
jeweilige Programm relevant ist, sondern ausschließlich Informationen zum
Fehler für den entsprechenden catch Block bereitstellen. Diese Informationen
sollten über den Konstruktor angenommen werden und den Nutzern des
Exception-Objekts via Eigenschaften lesend zur Verfügung gestellt werden.
› Die Basisklasse Exception enthält eine Eigenschaft Message vom Typ string, in
der mit Prosa beschrieben werden sollte, warum der Fehler aufgetreten ist. Das
dazugehörige Feld zu dieser Eigenschaft kann nur über den Konstruktor von
Exceptiongesetzt werden.
Behandlung mehrerer Exceptions
Nach dem try-Block können
mehrere catch-Blöcke folgen.
›Diese können unterschiedliche
Typen von Exceptions fangen.
› Es wird aber immer nur der erste
passende catch-Block
ausgeführt.
› Die Reihenfolge der Blöcke ist
daher wichtig (vgl. Exception
Hierarchie).
finally-Block
Manchmal muss noch Code
ausgeführt werden, auch wenn
ein Fehler aufgetreten ist.
› Z. B. wenn noch eine Datei
geschlossen werden muss.
› Dies kann in einem finally-Block
geschehen.
› Dieser wird immer ausgeführt,
egal ob ein Fehler aufgetreten ist
oder nicht.
finally-Block
Der finally-Block einer try-Anweisung wird unter fast allen Umständen
ausgeführt:
Nach der ungestörten Ausführung des try-Blocks
Nach einer Ausnahmebehandlung in einem catch-Block (auch beim Verlassen
des catch-Blocks durch eine neue Ausnahme)
Nach dem Auftreten einer unbehandelten Ausnahme im try-Block
Beim Verlassen der try-Anweisung durch eine goto-Anweisung im try-Block oder
in einem catch-Block
Beim Beenden der Methode durch eine return-Anweisung im try-Block oder in
einem catch-Block
Wann sollte man Exceptions auslösen?
Im Wesentlichen gibt es zwei Fälle:
Im Wesentlichen gibt es zGuard Clauses (dt. Schutzabfragen) – dies sind if Blöcke, die zu Beginn einer
Methode, die Parameter entgegennimmt, Exceptions auslösen. Diese if-
Abfragen werden genutzt, um die Parameterwerte auf Richtigkeit zu überprüfen.
Ist dies nicht der Fall, beispielsweise weil ein Index über die Größe des Arrays
hinausgeht oder weil eine Objektreferenz mit nullübergeben wurde, fliegt eine
Exception. Dies ist der häufigste Einsatz für
Ansonsten löst man häufig dann eine Ausnahme aus, wenn man erkennt, dass
ein Objekt in einem fehlerhaften Zustand übergehen würde – dies ist meistens
durch bestimmte Nebenbedingungen geschuldet (bspw. durch den Zustand
eines anderen Objekts). Dies ist meistens ein Hinweis auf schlechtes
Klassendesign, wenn solche Schritte notwendig