try
try
Beginn der Ausnahmebehandlung
Details
- Siehe: Verwandte Befehle ,
trysub,ErrGet (),ErrPos (),ErrSet (),ErrTryIgnore (),ErrTryCatch (),ErrIgnore (),ErrCall (), Fehlerbehandlung (Blog)
Mit der Anweisung für Ausnahmebehandlung kann bei einer Anweisungsfolge die Behandlung von Fehlern von den eigentlichen Anweisungen getrennt werden. Bei vielen Anweisungen wird nach der Anweisung geprüft, ob ein zulässiges Resultat vorhanden ist. In Abhängigkeit davon werden dann entweder weitere Anweisungen durchgeführt oder das unzulässige Resultat wird in irgendeiner Form behandelt. Diese Vorgehensweise kann Anweisungsfolgen stark verkomplizieren und auch unübersichtlicher machen.
Durch die Verwendung der Ausnahmebehandlung in Form des sogenannten try-Blocks kann dies vermieden werden. Dabei führen Verarbeitungsfehler zum Verlassen des try-Blocks. Der jeweilige Verarbeitungsfehler kann dann nach dem try-Block behandelt werden.
Zur Erkennung solcher Fehler existiert eine globale Fehlervariable, die entweder durch den Entwickler oder durch eine Systemfunktion gesetzt wird. Es existieren somit drei verschiedene Arten von Fehlern:
Applikationsfehler
Diese Fehler werden explizit durch den Programmierer definiert und mit dem Befehl ErrSet () gesetzt.
Funktionsfehler
Diese Fehler sind das Resultat einer Systemfunktion. Systemfunktionen, die den globalen Fehlerwert beeinflussen, sind am Ende dieses Abschnitts aufgelistet.
Laufzeitfehler
Dies sind Fehler, die während der Verarbeitung der Prozedur auftreten und normalerweise zum Abbruch der Prozedur führen (zum Beispiel "Division durch Null" oder "Deskriptor ungültig").
Der Fehlerwert kann mit dem Befehl ErrGet () abgefragt werden. Dabei sind positive Werte für die Resultate von Datensatzoperationen reserviert; der Wert 0 bezeichnet keinen Fehler; negative Werte von -1 bis -10000 sind für Systemfehler reserviert; negative Werte ab -10000 können durch den Entwickler für eigene Fehlerwerte benutzt werden.
Wird innerhalb eines try-Blocks eine Funktion aufgerufen, wirkt sich das Setzen des globalen Fehlerwertes auf die Durchführung der aufrufenden Funktion aus. Werden keine weiteren Maßnahmen ergriffen, wird die aufgerufene Funktion komplett durchgeführt. Hat am Ende der Funktion der globale Fehlerwert einen Wert ungleich 0 (_ErrOk), wird unmittelbar nach der Rückkehr der Funktion (noch vor der Zuweisung evtl. vorhandener Rückgabewerte) der try-Block verlassen.
Soll in der aufgerufenen Funktion ebenfalls eine Fehlerverarbeitung stattfinden, muss hier auch ein try-Block vorhanden sein. Soll sich der globale Fehlerwert nicht auf die aufrufende Funktion auswirken, muss der Fehlerwert mit ErrSet () auf den Wert _ErrOk gesetzt werden. Auch am Ende der Fehlerbehandlung sollte im Regelfall der Fehlerwert geleert werden.
Beispiel:
try
{
RecRead(1, 1, _RecLock); // Kunde lesen und sperren
RecLink(1, 2, 1, _RecLock) // Auftrag lesen und sperren
Inc(Cst.Sales, NettoVal); // Umsatz erhöhen
Ord.Cst.Booked # true; // Auftrag bei Kunden verbucht
RecReplace(2, 0); // Auftrag rückspeichern
RecReplace(1, 0); // Kunde rückspeichern
}
if (ErrGet() != _ErrOk)
{
...
ErrSet(_ErrOk);
}
In diesem Beispiel kann RecRead () bzw. RecLink () anstatt _rOk andere Resultate zurückliefern. Anstatt diese jetzt in der Anweisungsfolge zu überprüfen, wird bei einem solchen Resultat der try-Block verlassen. Danach wird mit ErrGet () geprüft, ob ein Fehler aufgetreten ist. Die globale Fehlervariable wird am Anfang des try-Blocks automatisch auf 0 (kein Fehler) gesetzt.
Innerhalb des try-Blocks reicht ein ErrSet () mit einem Wert ungleich 0 aus, um den Block zu verlassen. Dies gilt insbesondere für den Aufruf von eigenen Funktionen innerhalb des try-Blocks. Sofern innerhalb einer aufgerufenen Funktion ein ErrSet () erfolgt, wird der try-Block nach der Rückkehr der Funktion verlassen.
try-Blöcke können nicht geschachtelt werden. Eine Schachtelung ist nur insofern möglich, dass eine aufgerufene Funktion ebenfalls einen try-Block beinhalten kann, dann mit einer eigenen Fehlerbehandlung.
Wird innerhalb eines try-Blocks eine Funktion aufgerufen und in dieser Funktion kommt es zu einem Verarbeitungsfehler, wird die aufgerufene Funktion bis zum Ende durchgeführt. Ist zum Zeitpunkt der Rückkehr zur aufrufenden Funktion der globale Fehler noch gesetzt, wird nach der Rückkehr der Funktion die Verarbeitung nach dem try-Block fortgesetzt.
Soll die Verarbeitung sofort unterbrochen werden, wenn der globale Fehlerwert in einer aufgerufenen Funktion gesetzt wird, muss der trysub-Block verwendet werden.
Direkte Fehlerbehandlung
In manchen Fällen muss allerdings ein Fehler direkt bei der Anweisung behandelt werden, da der Fehler Bestandteil der normalen Verarbeitung ist und nach der Behandlung die Verarbeitung der Anweisungsfolge fortgesetzt wird. Zu diesem Zweck darf bei bestimmten Fehlerwerten der try-Block nicht verlassen werden (dies gilt vor allem bei Resultaten von Satzoperationen).
Mit dem Befehl ErrTryIgnore () kann veranlasst werden, dass der try-Block bestimmte Fehlerwerte ignoriert. Der Anweisung kann entweder ein einzelner Fehlerwert oder ein Bereich von Fehlerwerten übergeben werden. Dabei wird bei jedem Aufruf von ErrTryIgnore () der zu ignorierende Fehlerwert neu gesetzt. Bei mehreren Aufrufen summieren sich die Fehlerwerte demnach nicht.
Beispiel:
ErrTryIgnore(_rLocked) // Resultat _rLocked wird ignoriert
ErrTryIgnore(_rLocked, _rNoRec) // alle Resultate von RecRead
// werden von try ignoriert
ErrTryIgnore(_ErrOk) // von try werden jetzt keine
// Fehlerwerte mehr ignoriert
ErrTryIgnore(_ErrAll) // alle Fehlerwerte werden von
// try ignoriert
Die Anweisung ErrTryIgnore () muss immer innerhalb eines try-Blocks stehen.
Beispiel:
try
{
ErrTryIgnore(_rLocked, _rNoRec);
if (RecRead(1, 3, 0) != _rOk) // Resultat wird hier verarbeitet
{
Cst.Create();
RecInsert(1, 0);
}
// globalen Fehlerwert zurücksetzen, sonst wird der try-Block verlassen
ErrSet(_ErrOk);
ErrTryIgnore(_ErrOk);
...
}
Fehlerposition
Bei größeren try-Blöcken reicht der Fehlerwert vielfach zur anschließenden Behandlung nicht aus, da derselbe Fehlerwert an unterschiedlichen Stellen innerhalb des try-Blocks auftreten kann. Zur Feststellung der Fehlerposition können innerhalb des try-Blocks entsprechende Markierungen, sogenannte "Labels", verwendet werden. Ein Label beginnt mit einem Doppelpunkt, gefolgt von einem Namen und bezeichnet einen bestimmten Abschnitt im try-Block, nämlich von der Anweisung nach dem Label bis zum nächsten Label.
In der Fehlerbehandlung kann dann mit der Funktion ErrPos () die Position des aufgetretenen Fehlers bestimmt werden.
Beispiel:
try
{
:Kunde
RecRead(1, 1, _RecLock);
...
:Auftrag
RecRead(2, 1, _RecLock);
...
}
if (ErrGet() != _ErrOk)
{
switch (ErrPos())
{
case :Kunde : ...
case :Auftrag : ...
default : ...
}
...
ErrSet(_ErrOk);
}
ErrPos () liefert ein ganzzahliges Resultat, welches einem der definierten Labels entspricht. Ist ErrPos () gleich 0, trat der Fehler vor dem ersten Label auf.
Laufzeitfehler
Laufzeitfehler führen normalerweise zu einem Abbruch der Prozedur. Innerhalb von try-Blöcken können Laufzeitfehler abgefangen werden und wie andere Fehlerwerte in der Fehlerbehandlung verarbeitet werden. Dazu muss allerdings für jeden einzelnen Typ von Laufzeitfehler das Abfangen in try-Blöcken explizit ein- und ausgeschaltet werden.
Dies geschieht durch den Befehl ErrTryCatch (). Soll beispielsweise eine Division durch Null abgefangen werden, so geschieht dies durch ErrTryCatch( _ErrDivisionByZero , true ). Die Einstellungen zum Abfangen von Laufzeitfehlern sind global. Damit sind Veränderungen für jeden try-Block relevant.
Laufzeitfehler, die außerhalb eines try-Blocks auftreten, führen allerdings immer zum Prozedurabbruch. Soll vor diesem Prozedurabbruch der Laufzeitfehler protokolliert werden, kann mit dem Befehl ErrCall () eine Funktion registriert werden, die vor dem Prozedurabbruch aufgerufen wird.
Die Anweisung ErrTryCatch () kann außerhalb eines try-Blocks stehen.
Beispiel:
ErrTryCatch(_ErrDivisionByZero, true);
try
{
fResult # (10.0 / 0.0);
}
switch (ErrGet())
{
case _ErrDivisionByZero : ...
...
}
Über die Funktion ErrIgnore () kann die Generierung der Laufzeitfehler _ErrStringOverflow , _ErrCnv und _ErrDecimal abgeschaltet werden.
Folgende Anweisung setzen den globalen Fehlerwert und führen zum Verlassen des try-Blocks, wenn der entsprechende Fehler nicht mit der Anweisung ErrTryIgnore () übergangen wird. Die Anweisungen sind in der Hilfe mit gekennzeichnet.
BinCopyBinDeleteBinDirDeleteBinDirMoveBinDirOpenBinExportBinImportBinMoveBinOpenBinRenameBinUpdateDateMakeDbaConnectDllLoadFsiAttributesFsiDeleteFsiFileInfoFsiLockFsiOpenFsiPathChangeFsiPathDeleteFsiReadFsiRenameFsiSizeFsiWriteMailCloseOEMLoadOEMSaveRecBufCreateRecDeleteRecInsertRecLinkRecReadRecReplaceSckCloseSckConnectSckListenSckReadSckStartTlsSckWriteSelAddLinkSelAddSortFldSelClearSelCopySelDefQuerySelDeleteSelReadSelRecDeleteSelRecInsertSelRunSelStoreStoDirOpenStoOpenSysExecuteTextCopyTextCreateTextDeleteTextReadTextRenameTextWriteTimeMakeUrmDeleteUrmOpenUrmPermGetUrmPermGetRawUrmPropTypeUrmRead