C# Exception Handling: Exceptions richtig fangen und behandeln
Exceptions in C# richtig fangen: try-catch-finally, spezifische Exception-Typen und Best Practices – verständlich erklärt für alle IT-Einsteiger.
Von Marcel Schmidtpeter 09. Sept. 2026
Dein Programm läuft, der Nutzer tippt statt einer Zahl plötzlich „Hallo" ein - und die Konsole bricht mit einer roten Meldung ab: `System.FormatException: Input string was not in a correct format.` Kennst du? Genau solche Momente kosten Azubis Punkte in der IHK-Abschlussprüfung, Studenten Zeit in der Hausaufgabe und Berufseinsteiger ihr erstes Code Review. Mit sauberem C# Exception Handling gehören sie der Vergangenheit an.
Stell dir eine Exception wie den Not-Aus an einer Maschine vor: Sobald etwas Unerwartetes passiert, stoppt der normale Ablauf sofort. Exception Handling bedeutet, dass jemand danebensteht, der den Not-Aus auffängt und die Produktion kontrolliert weiterlaufen lässt.
Was ist eine Exception in C#?
Eine Exception ist ein Objekt, das die .NET-Laufzeitumgebung (die CLR, *Common Language Runtime*) erzeugt, wenn zur Laufzeit ein Fehler auftritt. Sie enthält eine Fehlerbeschreibung und den StackTrace - eine Liste der Methodenaufrufe, die zum Fehler geführt haben. Das ist im Prinzip dein Fahndungsfoto des Verbrechens.
Alle Exceptions in C# erben von der Klasse `System.Exception`. Die wichtigsten Eigenschaften:
Message: Die Klartext-Beschreibung des Fehlers
StackTrace: Der Weg durch den Code bis zum Absturz
InnerException: Eine mögliche ursächliche Exception, die mitverpackt wurde
Ein unbehandelter Fall sieht so aus:
string eingabe = "Hallo";
int zahl = int.Parse(eingabe); // wirft FormatException, Programm bricht abUnbehandelt heißt: Das Programm beendet sich sofort. Kein Speichern, kein Hinweis an den Nutzer, nichts.
Wie funktioniert das C# Exception Handling mit try, catch und finally?
Das Grundgerüst besteht aus drei Blöcken: `try` umschließt den riskanten Code, `catch` fängt den Fehler ab, `finally` läuft immer - egal ob Fehler oder nicht.
Block | Aufgabe |
`try` | Enthält den Code, der einen Fehler verursachen könnte |
`catch` | Wird ausgeführt, wenn eine Exception auftritt - dort reagierst du auf den Fehler |
`finally` | Läuft garantiert immer, auch bei `return` oder unbehandelten Fehlern. Ideal fürs Aufräumen (z. B. Dateien schließen) |
try
{
string inhalt = File.ReadAllText("daten.txt");
Console.WriteLine(inhalt);
}
catch (FileNotFoundException)
{
Console.WriteLine("Die Datei wurde nicht gefunden.");
}
finally
{
Console.WriteLine("Dieser Code laeuft immer.");
}Merke: Der `finally`-Block läuft in jedem Fall - selbst wenn im `try`-Block ein `return` steht oder eine Exception nicht abgefangen wird.
Welche Exception-Typen gibt es in C#?
Die .NET-Bibliothek bringt zahlreiche fertige Exception-Klassen für typische Situationen mit. Diese sechs begegnen dir am häufigsten:
Exception | Tritt auf, wenn ... |
`FormatException` | `int.Parse` einen Text erhält, der keine Zahl ist |
`NullReferenceException` | du auf einem `null`-Objekt eine Methode aufrufst |
`DivideByZeroException` | eine Ganzzahldivision durch 0 erfolgt |
`IndexOutOfRangeException` | ein Array-Index außerhalb der Grenzen liegt |
`FileNotFoundException` | eine Datei nicht existiert |
`OverflowException` | ein Zahlenbereich überschritten wird |
Ein Detail, das oft überrascht:
Achtung: `DivideByZeroException` fliegt nur bei Ganzzahlen. `1.0 / 0.0` mit `double` ergibt `Infinity` - ohne Exception. Erst wenn du dieses Ergebnis in einen `int` umwandelst, gibt es Ärger.
Die `NullReferenceException` ist laut Microsoft die häufigste Exception überhaupt. Wie du ihr von vornherein ausweichst, erklärt unser Beitrag zu C# Nullable.
Wie fängst du mehrere Exceptions in der richtigen Reihenfolge ab?
Fängst du mehrere Exception-Typen ab, gilt die Regel: vom Speziellen zum Allgemeinen. Der Compiler prüft die `catch`-Blöcke von oben nach unten. Ein allgemeiner Block zuerst würde alle spezifischen dahinter unerreicherbar machen - der Compiler meldet das sogar als Fehler.
So geht's richtig:
string eingabe = "Hallo"; // kommt z. B. vom Nutzer
try
{
int zahl = int.Parse(eingabe);
Console.WriteLine(100 / zahl);
}
catch (FormatException)
{
Console.WriteLine("Das war keine Zahl.");
}
catch (DivideByZeroException)
{
Console.WriteLine("Division durch 0 ist nicht erlaubt.");
}
catch (Exception ex)
{
Console.WriteLine("Unerwarteter Fehler: " + ex.Message);
}Merke: Fange immer so spezifisch wie möglich ab. `catch (Exception)` gehört nur ganz ans Ende als Sicherheitsnetz - oder in die oberste Ebene deiner Anwendung.
Wie wirfst du eigene Exceptions mit throw?
Mit `throw` meldest du selbst einen Fehler - typischerweise in Methoden, wenn ein übergebener Wert unzulässig ist. So kann der Aufrufer entscheiden, wie er damit umgeht:
private double preis;
public void SetzePreis(double preis)
{
if (preis < 0)
{
throw new ArgumentException("Preis darf nicht negativ sein.", nameof(preis));
}
this.preis = preis;
}`nameof(preis)` liefert den Namen des Parameters als String - praktisch, weil Visual Studio beim Umbenennen mitspielt. Für fachliche Fehler (z. B. „Preis übersteigt Budget") lohnt sich eine eigene Exception-Klasse, die von `Exception` erbt:
public class UngueltigerPreisException : Exception
{
public UngueltigerPreisException(string message) : base(message)
{
}
}Praxisbeispiel: Ein crash-sicherer Mini-Rechner
Hier ein vollständiges, lauffähiges Programm, das jede Eingabe überlebt. Kopiere es in eine neue Konsolen-App und teste es:
using System;
class Programm
{
static void Main()
{
while (true)
{
Console.Write("Gib eine Zahl ein (oder 'x' fuer Ende): ");
string eingabe = Console.ReadLine();
if (eingabe == null || eingabe.ToLower() == "x")
{
break;
}
try
{
int teiler = int.Parse(eingabe);
Console.WriteLine($"100 geteilt durch {teiler} ergibt {100 / teiler}");
}
catch (FormatException)
{
Console.WriteLine("Das war keine ganze Zahl. Versuch es nochmal.");
}
catch (DivideByZeroException)
{
Console.WriteLine("Durch 0 darfst du nicht teilen.");
}
}
Console.WriteLine("Programm beendet.");
}
}Das Programm stürzt bei keiner Eingabe ab - genau das erwartet man in Betrieb und Prüfung von robustem Code. Details und weitere Exception-Klassen findest du in der offiziellen Dokumentation auf Microsoft Learn.
Diese 3 Anfängerfehler solltest du vermeiden
Fehler 1: Leeres catch oder pauschales catch (Exception). Ein `catch { }` ohne Inhalt verschluckt den Fehler kommentarlos. Warum ist das schlimm? Weil du später stundenlang nach einem Bug suchst, der längst gemeldet wurde - nur niemand hat hingesehen. Fang spezifisch ab und schreibe mindestens eine Log-Ausgabe.
Fehler 2: throw ex statt throw. Beim Weiterleiten einer Exception zerstört `throw ex` den ursprünglichen StackTrace. Du verlierst die Information, wo der Fehler wirklich entstand:
catch (Exception ex)
{
Console.WriteLine("Fehler geloggt: " + ex.Message);
throw; // StackTrace bleibt erhalten -- verwende throw, nicht throw ex!
}Fehler 3: Exceptions als normale Flusskontrolle. Erwartbare Situationen wie falsche Nutzereingaben fängst du besser gar nicht erst mit Exceptions ab, sondern prüfst sie direkt:
if (int.TryParse(eingabe, out int zahl))
{
Console.WriteLine(100 / zahl);
}
else
{
Console.WriteLine("Keine gueltige Zahl eingegeben.");
}`int.TryParse` gibt ein `bool` zurück und wirft niemals eine `FormatException`. Das ist schneller und lesbarer - die Details erklärt die API-Doku zu int.TryParse.
Dein Übungstipp
Nimm eine deiner alten Konsolen-Apps (aus dem Betrieb, dem Studium oder einem Tutorial) und versuche, sie bewusst zum Absturz zu bringen. Teste: leere Eingabe, nur Buchstaben, `0`, riesige Zahlen, negative Werte. Jeden gefundenen Crash fixt du mit `try-catch` oder `TryParse`. Diese Methode simuliert genau, was ein Tester oder dein Ausbilder mit deinem Code macht - und du bist vorbereitet.
FAQ: Häufige Fragen zu C# Exception Handling
Wann läuft der finally-Block?
Immer - egal ob eine Exception auftrat, ob sie abgefangen wurde oder ob im `try`-Block ein `return` steht. Deshalb nutzt man ihn für Aufräumarbeiten wie das Schließen von Dateien oder Verbindungen.
Was ist der Unterschied zwischen throw und throw ex?
`throw` wirft die gefangene Exception erneut und behält den ursprünglichen StackTrace. `throw ex` setzt den StackTrace neu - die Ursprungsstelle des Fehlers geht verloren. Nutze daher innerhalb von `catch` immer `throw`.
Sollte ich überall catch (Exception) schreiben?
Nein. Der Basistyp fängt alles ab, auch Fehler, die du gar nicht behandeln kannst (z. B. Speichermangel). Sinnvoll ist `catch (Exception)` nur ganz oben in der Anwendung als letzte Instanz, damit das Programm nicht komplett abstürzt.
Wann erstelle ich eine eigene Exception-Klasse?
Wenn ein fachlicher Fehler auftritt, den die Standard-Exceptions nicht beschreiben - etwa „Budget überschritten" oder „Lagerbestand zu niedrig". So kann Aufrufer-Code gezielt auf genau diesen Fall reagieren.
Gilt das Konzept auch in anderen Sprachen?
Ja, try-catch-finally existiert in fast allen modernen Sprachen. Wer parallel Python lernt, findet die Entsprechung mit `try except finally` in unserem Artikel zu Python Exception Handling.
Fazit
C# Exception Handling ist kein optionaler Feinschliff, sondern Grundvoraussetzung für professionellen Code: `try` umschließt den riskanten Code, `catch` fängt spezifische Fehler ab, `finally` räumt garantiert auf. Fang so spezifisch wie möglich, nutze `TryParse` für erwartbare Eingaben und `throw` statt `throw ex` beim Weiterleiten. Mit diesen Regeln übersteht dein Programm jede Nutzereingabe - und du überstehst jede Prüfung.
Wenn du bei C# oder anderen IT-Themen Unterstützung brauchst, schau bei study-it.education vorbei. Dort bekommst du individuelle Nachhilfe - ob für die IHK-Prüfung als Fachinformatiker, fürs Studium oder für den Berufseinstieg.
Brauchst du jemand, der das mit dir durchgeht?
Statt nochmal lesen: 30 min mit einem Senior-Dev.
Kostenloses Erstgespräch buchen →
Exceptions in C# richtig fangen: try-catch-finally, spezifische Exception-Typen und Best Practices – verständlich erklärt für alle IT-Einsteiger.
marcel.schmidtpeter@study-it.education →Mehr Lesestoff
C# JSON mit System.Text.Json lesen & schreiben – einfach erklärt
JSON-Daten in C# lesen und schreiben? Mit System.Text.Json gelingt dir Serialisierung & Deserialisierung – einfach erklärt für alle IT-Einsteiger.
C# xUnit Unit Test: So schreibst du deine ersten Unit Tests
Unit Tests mit xUnit machen deinen C#-Code belastbar. In diesem Tutorial lernst du [Fact], [Theory] und Assert kennen – für Einsteiger erklärt.
C# Datenbank verbinden: ADO.NET & Entity Framework einfach erklärt
So greifst du aus C# auf Datenbanken zu: mit ADO.NET für direktes SQL oder EF Core als modernem ORM – beide Wege mit Beispielen erklärt.