1. Einführung
Stell dir vor, du schreibst einen Taschenrechner zum Dividieren von zwei Zahlen. Alles läuft super, bis jemand auf die Idee kommt, durch Null zu teilen:
int a = 10;
int b = 0;
int result = a / b; // Boom!
In diesem Moment "crasht" das Programm und der User sieht eine fiese Fehlermeldung. Genau das ist eine Ausnahmesituation – ein Ereignis, das im "normalen" Ablauf nicht passieren sollte und besondere Aufmerksamkeit braucht.
Exception – das ist ein spezieller Mechanismus, mit dem .NET deinem Programm mitteilt, dass etwas Unerwartetes passiert ist und die Ausführung abgebrochen oder speziell behandelt werden muss.
Wenn ein Laufzeitfehler passiert (zum Beispiel Division durch Null, Zugriff auf eine nicht vorhandene Datei oder – der Klassiker – Dereferenzierung von null), "wirft" .NET (throw) ein spezielles Exception-Objekt. Dann wird ein Handler gesucht, der die Situation "fangen" (catch) und passend reagieren kann.
Warum nicht einfach einen "Fehlercode" zurückgeben?
Man könnte auch einen Fehlercode zurückgeben – viele alte Sprachen (Pascal, C, und auch manche modernen APIs) machen das so. Aber das ist unpraktisch und gefährlich: Man vergisst leicht, den Fehlercode zu prüfen (wir hoffen ja immer aufs Beste) – und es ist extrem schwer herauszufinden, wo genau es schiefgelaufen ist. Exceptions erlauben es, Fehler zentral zu verfolgen und flexibel darauf zu reagieren, ohne den Code mit Checks zuzumüllen.
2. "Werfen" einer Exception
Exceptions können automatisch entstehen – bei einem Laufzeitfehler – oder man wirft sie selbst mit dem Schlüsselwort throw:
int[] arr = new int[2];
arr[10] = 5; // Exception wird automatisch geworfen: System.IndexOutOfRangeException
throw new Exception("Absolute Katastrophe!"); // Manuell Exception werfen
Auch wenn du denkst, dein Programm ist perfekt designt, kann immer etwas Unerwartetes passieren: Der User schließt die Datei, das Internet fällt aus, jemand zieht den Stecker vom Rechner (naja, fast).
Zum Glück hat .NET uns nicht nur das "Werfen" von Exceptions gegeben, sondern auch Möglichkeiten, sie abzufangen und zu behandeln – darum kümmern wir uns gleich.
3. Lebenszyklus einer Exception: von throw bis catch
Wenn im Code etwas schiefgeht, startet .NET das "Notfall-Prozedere":
- Erstellt ein Exception-Objekt (zum Beispiel IndexOutOfRangeException).
- Wirft es mit dem Schlüsselwort throw.
- Sucht einen Handler: Geht den Call-Stack von unten nach oben durch (vom aktuellen zur aufrufenden Methode) – sucht den ersten catch-Block, der zum Typ der geworfenen Exception passt.
- Wenn ein Handler gefunden wird – läuft das Programm im catch-Block weiter.
- Wenn kein Handler gefunden wird – beendet sich das Programm mit einer Fehlermeldung und zeigt den "Call Stack" mit Details an.
Das ist wie ein spannender Ball, der die Treppe runterrollt – solange, bis ihn jemand auffängt, kann er ziemlich weit "springen".
4. Exception-Hierarchie in .NET
Das Baumdiagramm von "Eltern und Kindern"
In .NET (wie in den meisten OOP-Sprachen) sind Exceptions als Klassen umgesetzt, die voneinander erben und eine ganze Hierarchie bilden.
Alle haben einen gemeinsamen Vorfahren – die Basisklasse System.Exception.
System.Object
└─ System.Exception
├─ System.SystemException
│ ├─ System.NullReferenceException
│ ├─ System.IndexOutOfRangeException
│ ├─ System.DivideByZeroException
│ ├─ System.OutOfMemoryException
│ └─ ... und viele andere
├─ System.IO.IOException
│ ├─ System.IO.FileNotFoundException
│ ├─ System.IO.DirectoryNotFoundException
│ └─ ...
├─ System.ArgumentException
│ ├─ System.ArgumentNullException
│ └─ System.ArgumentOutOfRangeException
└─ (deine eigenen Exception-Klassen)
Warum Klassen?
Dank der Klassenhierarchie kann man gleich eine ganze "Klasse" von Problemen abfangen – zum Beispiel alle Fehler, die mit Funktionsargumenten zu tun haben (ArgumentException und deren Nachfolger). Außerdem kannst du eigene Fehlertypen hinzufügen (mehr dazu in den nächsten Vorlesungen).
Die beliebtesten .NET-Exceptions
- NullReferenceException – Versuch, auf eine Methode oder Eigenschaft eines Objekts zuzugreifen, das null ist. Ein alter Bekannter!
- DivideByZeroException – Division durch Null.
- IndexOutOfRangeException – Array-Index außerhalb des gültigen Bereichs.
- ArgumentException, ArgumentNullException, ArgumentOutOfRangeException – Fehlerhafte Methodenparameter.
- FileNotFoundException, IOException – Probleme beim Arbeiten mit Dateien.
- InvalidOperationException – Operation im aktuellen Objektzustand nicht möglich.
- FormatException – Falsches Datenformat (z.B. Versuch, "abcd" in eine Zahl zu konvertieren).
5. Beispiele: Wie verschiedene Exceptions "abgehen"
Schauen wir uns mal Codebeispiele an, die verschiedene Exceptions auslösen.
Beispiel 1: NullReferenceException
string? str = null;
Console.WriteLine(str.Length); // Hier "Boom!" – str ist null
Ausgabe:
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
Beispiel 2: DivideByZeroException
int a = 42;
int b = 0;
int c = a / b; // Gefährlich! Division durch 0
Ausgabe:
Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
Beispiel 3: IndexOutOfRangeException
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]); // Kein Element mit Index 5
Hier gibt's offensichtlich zu viele Indizes, und die Ausgabe ist:
Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.
Beispiel 4: FileNotFoundException
using System.IO;
string content = File.ReadAllText("secret.txt");
Wenn du keine Datei namens "secret.txt" hast, bekommst du ungefähr diese Meldung:
Unhandled exception. System.IO.FileNotFoundException: Could not find file '/Users/zapp/RiderProjects/ConsoleApp1/ConsoleApp1/bin/Debug/net9.0/secret.txt'.
Beispiel 5: FormatException
string input = "dreizehn";
int number = int.Parse(input); // String ist keine Zahl
Ausgabe:
Unhandled exception. System.FormatException: The input string 'dreizehn' was not in a correct format.
6. Wie kannst du das Wissen nutzen?
Zu verstehen, wie Exceptions funktionieren, ist echt wichtig für jeden Entwickler. Das ist nicht nur "Theorie um der Theorie willen", sondern ein praktischer Skill, der direkt die Stabilität deiner Programme beeinflusst. Wenn du weißt, wie du Fehler richtig behandelst, crasht dein Programm nicht beim ersten Problem, sondern sagt dem User freundlich und klar, was schiefgelaufen ist. Das macht es zuverlässiger, professioneller und einfach userfreundlicher.
Und das ist nicht nur bequem. In Vorstellungsgesprächen kommen oft Fragen zur Exception-Mechanik, zu den Typen von Exception und wie das Ganze in .NET funktioniert. Ein gutes Verständnis bringt dir also auch Pluspunkte beim Job.
Außerdem wirst du in echten Projekten noch oft auf Exceptions stoßen. Arbeiten mit Dateien, Netzwerk, Datenbanken, externen Bibliotheken und Frameworks – überall werden Exceptions genutzt. Also besser gleich verstehen, wie das läuft, damit es später keine bösen Überraschungen gibt.
7. Typische Fehler im Umgang mit Exceptions
Fehler Nr. 1: Exceptions komplett ignorieren.
Manche Anfänger (und manchmal auch erfahrene Entwickler) sehen Exceptions als etwas Nerviges oder Störendes. Sie ignorieren sie einfach oder – noch schlimmer – packen den Code in einen catch { } und machen gar nichts. Das Programm läuft dann "still" in einem komischen Zustand weiter und die Ursache des Fehlers ist nicht mehr nachvollziehbar.
Fehler Nr. 2: Verwechslung von Exceptions und normalen Fehlern.
Oft wird vergessen, dass nicht jeder Fehler per try-catch abgefangen werden muss. Wenn der User zum Beispiel falsche Daten eingibt, sollte man das lieber vorher prüfen, statt auf eine FormatException zu hoffen oder Exceptions als Logik-Mechanismus zu missbrauchen. Exceptions sind für Ausnahmefälle, nicht für Routine.
Fehler Nr. 3: Falsches Verständnis der Exception-Hierarchie.
Manchmal wird versucht, eine zu allgemeine Klasse (Exception) abzufangen und fängt dann alles ab, auch Fehler, die man besser unbehandelt lässt. Oder man fängt zu spezifische Typen (IndexOutOfRangeException, NullReferenceException) und vergisst, dass auch andere auftreten können. Es ist wichtig zu verstehen, wie die Exception-Hierarchie in .NET aufgebaut ist und was du wirklich behandeln willst.
Und das Wichtigste – denk dran: Exceptions in C# sind kein Weltuntergang und kein "alles ist verloren"-Signal, sondern einfach ein Mechanismus, um auf einen besonderen Ablauf umzuschalten. Ein mächtiges Tool, wenn man es richtig nutzt.
GO TO FULL VERSION