Fehlerbehandlung mit Struktur (Teil 2)
Kommentare

Weitergabe von Fehlern
Wenn möglich, sollten alle Fehler sofort an dem Ort der Entstehung behandelt werden. Ist das nicht möglich, muss der Aufrufer die Fehlerbehandlung übernehmen. In allen anderen

Weitergabe von Fehlern

Wenn möglich, sollten alle Fehler sofort an dem Ort der Entstehung behandelt werden. Ist das nicht möglich, muss der Aufrufer die Fehlerbehandlung übernehmen. In allen anderen Fällen sollte dem Aufrufer aber auch mitgeteilt werden, dass der Aufruf fehlerhaft verlief. Generell existieren dazu drei Ansätze:

  1.  Der Fehler wird nicht selbst behandelt, sondern der Aufrufer ist verpflichtet, den Fehler zu behandeln.
  2. Der Fehler wird behandelt, eventuelle Aufräumarbeiten werden durchgeführt und der Fehler wird erneut ausgelöst.
  3. Der Fehler wird aufgefangen, eventuelle Aufräumarbeiten werden durchgeführt und ein neuer Fehler mit zusätzlichen Informationen wird ausgelöst.

Listing 1 zeigte bereits für den ersten Fall ein entsprechendes Beispiel. Die mögliche Division durch 0 wird nicht innerhalb der Methode Calculate behandelt, sondern der Aufrufer ist dafür verantwortlich. Ein Beispiel für die zweite Methode zeigt Listing 2. Der Fehler wird sofort behandelt. Hierbei können eventuelle Aufräumarbeiten durchgeführt werden. Danach wird der Fehler durch den Aufruf throw erneut ausgelöst, um den Aufrufer über den Fehler ebenfalls zu informieren. Die letzte Möglichkeit zeigt Listing 3. Dort wird ebenso zunächst der Fehler direkt behandelt, zusätzlich wird aber eine neue Ausnahme erstellt und die ursprüngliche Ausnahme der neuen hinzugefügt. So können zusätzliche Informationen an den Aufrufer übergeben werden.

Listing 2

public static void Calculate(int divBy)
{
  try
  {
    int result = 100 / divBy;
  }
  catch (DivideByZeroException dbze)
  {
    // Aufräumen, wenn notwendig
    throw;
  }      
}  

Listing 3

public static void Calculate(int divBy)
{
  try
  {
    int result = 100 / divBy;
  }
  catch (DivideByZeroException dbze)
  {
    throw new NotSupportedException("
        Der übergebene Parameterwert ist nicht zulässig", dbze);
  }      
}  

Stacktrace & Co. erhalten

Generell existieren die drei folgenden Möglichkeiten, einen Fehler weiterzugeben:

  • throw new Exception(„“,[Exception Variable])
  • throw;
  • throw [Exception Variable];

Die erste Variante erstellt eine neue Ausnahme und fügt die behandelte Ausnahme der neuen als innere Ausnahme (InnerException) hinzu (vgl. auch Listing 3). Die zweite und dritte Variante lösen die behandelte Ausnahme nochmals aus. Die drei Varianten unterscheiden sich jedoch in der Art und Weise, wie mit inneren Informationen, zum Beispiel Stacktrace und Target, verfahren wird. Die ersten beiden Varianten erhalten die originalen Werte der ursprünglichen Ausnahme. Bei der dritten Variante hingegen gehen die ursprünglichen Informationen verloren. Die neu geworfene Ausnahme verliert unter anderem die ursprünglichen Werte der Eigenschaften Stacktrace und Target und ersetzt sie durch Informationen des aktuellen Kontexts. In manchen Situationen kann das ein gewünschtes Verhalten sein, in der Regel erschwert es aber nur die Fehleranalyse. 

Eigene Fehlerklassen

Das .NET Framework beinhaltet bereits eine beachtliche Menge an XXXException-Klassen. Für eigene Anwendungen ist es aber auch sinnvoll, eigene, auf die speziellen Bedürfnisse angepasste Ausnahmeklassen zu definieren und zu verwenden. Das ist auch nicht schwer. Eigene Ausnahmeklassen müssen lediglich von einer der vorhandenen XXXException oder von der allgemeinen Exception-Klasse ableiten. Listing 4 demonstriert die Realisierung einer eigenen Ausnahmeklasse. Gemäß dem empfohlenen Designmuster besitzt die umgesetzte Ausnahmeklasse drei Konstruktoren. Dabei ist der Konstruktor für die Übergabe einer inneren Ausnahme wichtig, da ansonsten Instanzen der eigenen Ausnahmeklasse nicht verschachtelt werden könnten. Die so bereitgestellte Ausnahmeklasse kann genauso wie die bereits eingebauten Ausnahmenklassen verwendet werden.

Listing 4

public class InvalidValueException : Exception
{
  public InvalidValueException()
  {
  }
  public InvalidValueException(string message) 
    : base(message)
  {     
  }
  public InvalidValueException(string message, Exception innerException)
    : base(message,innerException)
  {      
  }
  public int WrongValue { get; set; }
}  

„finally“-Block

Passend zum Abschluss der aktuellen C#-Kolumne geht es um den finally-Block. Der finally-Block ist optional und muss nur bei Bedarf implementiert werden. Typischerweise werden im finally-Block Aufräumarbeiten durchgeführt, die auf jeden Fall, egal ob ein Fehler aufgetreten ist oder nicht, durchzuführen sind. In der Regel befinden sich hier Aktionen wie das Schließen eines Datenstroms (Datenbank, Datei etc.) oder/und das Schreiben eines Protokolleintrags. Im Gegensatz zu den catch-Blöcken kann ein finally-Block nur einmal pro try-catch-Konstrukt definiert werden.

Zusammenfassung

Das .NET Framework stellt mit dem try-catch-finally-Konstrukt eine effektive Möglichkeit bereit, um Fehler optimal zu behandeln. Durch die mehr oder weniger erzwungene Fehlerbehandlung entstehen stabilere Anwendungen. Auch Fehler, die nicht selbst behandelt wurden, werden von der Laufzeitumgebung aufgefangen und liefern somit wertvolle Informationen für eine effiziente Fehleranalyse. Auf MSDN sind zahlreiche weitere ausführliche Erläuterungen zur Fehlerverwaltung zu finden. 

Marc André Zhou ist als freiberuflicher .NET-Technologieberater tätig. Seine Schwerpunkte sind .NET-Entwicklung, SharePoint, Softwarearchitekturen und Frameworks. Sie erreichen ihn unter zhou@dev-sky.net.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -