Programmierung

Fehlerbehandlung (Teil 3)

Im 3. Teil der Artikelserie zur Fehlerbehandlung zeige ich anhand von Beispielen, wie Sie zulässige Fehlerfälle bei der Ausnahmebehandlung ignorieren und sogar auf Laufzeitfehler reagieren können.


Ausnahmen die keine sind

In einigen Fällen kann es sinnvoll sein, bestimmte Fehler innerhalb einer Ausnahmebehandlung nicht als Ausnahme zu behandeln, sondern die Reaktion auf diesen Zustand schon während der Verarbeitung durchzuführen.

Ein typischer Anwendungsfall sind Resultate von Datenbankfunktionen auf Datensätze, Texte, binäre Objekte oder ähnliches. Diese Funktionen lösen eine Ausnahme aus, wenn die angeforderte Aktion, wie zum Beispiel das Lesen, Schreiben, Sperren oder Löschen von Daten, nicht ordnungsgemäß durchgeführt werden konnte, beispielsweise weil die angeforderten Daten nicht vorhanden oder bereits gesperrt sind.

Mit der Funktion ErrTryIgnore() können ein oder mehrere Ausnahmen bei der Ausnahmebehandlung ignoriert werden, so dass noch innerhalb des Programmablaufs darauf reagiert werden kann. Die Funktion erwartet einen einzelnen oder einen Bereich von Fehlerwerten die nicht als Ausnahme behandelt werden sollen. Die Funktion muss innerhalb des try-Blocks aufgerufen werden, für den sie gelten soll.

Beispiel

try
{
  // Resultate von _rLocked (1) bis _rNoRec (5)
  // nicht als Ausnahmen behandeln
  ErrTryIgnore(_rLocked, _rNoRec);

  // RecRead() löst die Ausnahme _rNoRec aus, wenn keine
  // weiteren Datensätze mehr vorhanden sind
  for   tResultLoop # RecRead(aTable, aKey, _RecFirst);
  loop  tResultLoop # RecRead(aTable, aKey, _RecNext);
  while (tResultLoop < _rNoRec)
  {
    // Ausnahmen von SckWrite() führen weiterhin zum
    // Verlassen des try-Blocks
    tSck->SckWrite(_SckLine, 'foo: ' + FldAlpha(aTable, 1, 1));
    tSck->SckWrite(_SckLine, 'bar: ' + FldAlpha(aTable, 1, 2));
    tSck->SckWrite(_SckLine, 'baz: ' + FldAlpha(aTable, 1, 3));
  }
}

// Fehlerbehandlung
switch (ErrGet())
{
  // Fehler beim Schreiben auf Socket
  case _ErrSckWrite : ...
  case _ErrTimeout  : ...
}

Laufzeitfehler

Laufzeitfehler sind Fehler die normalerweise zum Abbruch der Prozedur führen, wie zum Beispiel „Deskriptor ungültig“ oder „Division durch Null“, da ohne Behandlung kein reguläres Fortführen der Verarbeitung mehr gewährleistet werden kann. Innerhalb der Ausnahmebehandlung lassen sich selbst solche Fehler berücksichtigen. Dabei wird die Verarbeitung bei Auftreten eines Laufzeitfehlers nach wie vor abgebrochen, allerdings wird sie nach dem try-Block fortgesetzt.

Ein praktisches Szenario für die Behandlung von Laufzeitfehlern ist die garantierte Fortsetzung der Prozedur durch das Abfangen sämtlicher möglicher Laufzeitfehler. Dadurch kann möglicherweise fehlerbehafteter Prozedurcode ausgeführt werden, ohne dass im Fehlerfall die komplette Verarbeitung abbricht.

Durch den Aufruf der Funktion ErrTryCatch() kann die Behandlung eines oder aller Laufzeitfehler aktiviert oder deaktiviert werden. Durch mehrfaches Aufrufen können auch mehrere Laufzeitfehler behandelt werden. Die Behandlung gilt für alle try-Blöcke, die zwischen dem Aktivieren und dem Deaktivieren durchlaufen werden.

Beispiel

// Behandlung aller Laufzeitfehler aktivieren
ErrTryCatch(_ErrAll, true);
try
{
  // Aufruf einer benutzerdefinierten Prozedur
  // mit möglicherweise fehlerbehaftetem
  // Prozedurcode der Laufzeitfehler auslösen könnte
  Call(aProc);
}
// Behandlung aller Laufzeitfehler deaktivieren
ErrTryCatch(_ErrAll, false);

// Verarbeitung wird auch bei Laufzeitfehler fortgesetzt
...

Bestimmte Laufzeitfehler können auch ohne Ausnahmebehandlung unterdrückt werden, so zum Beispiel „Typkonvertierung nicht möglich” bei einer Konvertierungsfunktion oder „Alphawert zu lang” bei der Zuweisung einer Zeichenkette. Wird ein solcher Fehler unterdrückt, wird bei einer Konvertierung ein leeres Resultat zurückgegeben und bei einer Zuweisung eine zu lange Zeichenkette abgeschnitten.

Besonders hilfreich ist diese Technik bei der Verarbeitung von benutzerdefinierten Daten, deren Korrektheit nicht durch entsprechende Eigenschaften der Eingabeobjekte sichergestellt werden kann. Bei einem Web-Formular ist das beispielsweise der Fall.

Unter Verwendung der Funktion ErrIgnore() können bestimmte Laufzeitfehler ignoriert oder wieder ausgelöst werden.

Beispiel

// Laufzeitfehler „Typkonvertierung nicht möglich“ ignorieren
ErrIgnore(_ErrCnv, true);
// Laufzeitfehler „Alphawert zu lang“ ignorieren
ErrIgnore(_ErrStringOverflow, true);

// Löst Laufzeitfehler _ErrCnv aus,
// falls Konvertierung nicht möglich
tInt # CnvIA(tUserInput1);

// Löst Laufzeitfehler _ErrStringOverflow aus,
// falls Zeichenkette zu lang
tAlpha80 # tUserInput2;
// Laufzeitfehler „Alphawert zu lang“ nicht mehr ignorieren
ErrIgnore(_ErrStringOverflow, false);
// Laufzeitfehler „Typkonvertierung nicht möglich“ nicht mehr ignorieren
ErrIgnore(_ErrCnv, false);
1 Kommentar

1 Kommentar zu “Fehlerbehandlung (Teil 3)”

  1. eine vielgebrauchte Stelle für Beispiel 2 sind auch Com-Schnittstellen. Insbesondere das Auslesen von Mails aus Outlook würde ohne Try praktisch überhaupt nicht funktionieren (Eigenschaft ungültig)

Kommentar abgeben