Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Hinweis
Gemeinschaftsinteressengruppen sind inzwischen von Yammer zu Microsoft Viva Engage gewechselt. Um einer Viva Engage Community beizutreten und an den neuesten Diskussionen teilzunehmen, füllen Sie das Formular Request access to Finance and Operations Viva Engage Community aus und wählen Sie die Community aus, der Sie beitreten möchten.
In diesem Artikel wird die Ausnahmebehandlung in X++ beschrieben. Fehler mit dem Wurf beheben, versuchen... Catch und Retry Statements schließlich, um Ausnahmen zu generieren und zu handhaben.
Eine Ausnahme ist ein geregelter Sprung weg von der Reihenfolge der Programmausführung. Die Blöcke try...catch und die Art der geworfenen Ausnahme bestimmen die Anweisung, bei der die Programmausführung wieder aufgenommen wird. Eine Ausnahme wird durch einen Wert der Exception-Enumeration oder eine Instanz von dargestellt. NET-Klasse oder einer von ihr abgeleiteten System.Exception Klasse. Eine Ausnahme, die du oft einsetzt, ist der Exception::error Enum-Wert. Eine gängige Praxis ist, Diagnoseinformationen in das Infolog zu schreiben, bevor die Ausnahme ausgelöst wird.
Die Global::error-Methode ist oft die beste Methode, um Diagnoseinformationen in das Infolog zu schreiben. Die Methode kann z. B. einen Eingabeparameterwert empfangen, der ungültig ist. In diesem Fall kann die Methode eine Ausnahme auslösen, um die Steuerung sofort an einen catch-Codeblock zu übertragen, der Logik zum Behandeln dieser Fehlersituation enthält. Du musst nicht unbedingt wissen, wo sich der Fangblock befindet, der die Kontrolle erhält, wenn die Ausnahme geworfen wird.
throw-Anweisungen
Verwenden Sie das Throw-Schlüsselwort, um einen Ausnahme-Enum-Wert zu werfen. Die folgende Anweisung löst z. B. eine Fehlerausnahme aus.
throw Exception::error;
Anstatt einen Enum-Wert zu werfen, verwenden Sie die Ausgabe der Global::error-Methode als Operanden für throw.
throw Global::error('The parameter value is invalid.');
Die Global::error-Methode kann eine Beschriftung automatisch in den entsprechenden Text umwandeln. Mit dieser Funktion können Sie Code schreiben, der leichter lokalisiert werden kann.
throw Global::error("@SYS98765");
Man kann die statischen Methoden auf der Global-Klasse ohne das Präfix Global:: aufrufen. Zum Beispiel kann man die Global::error-Methode so aufrufen.
error('My message.');
Verwenden Sie das Throw-Schlüsselwort , um .NET-Ausnahmen sowie die Werte des aufgezählten Exception-Typs zu werfen.
throw new System.InvalidOperationException("This function is not allowed");
Verwenden Sie das Wurf-Schlüsselwort allein innerhalb eines Fangblocks. In diesem Fall verhält sich Throw wie die Rethrow-Aussage in C#. Die ursprüngliche Ausnahme-, Ausnahme-Nachricht und ihr Kontext wie Aufrufstapel werden neu geworfen und stehen allen Catch-Anweisungen im Aufrufcode zur Verfügung.
try
{
throw Exception::error;
}
catch
{
// locally handle exception
// then rethrow for caller
throw;
}
try-, catch-, finally- und retry-Anweisungen
Wenn eine Ausnahme auftritt, verarbeitet das System sie zunächst über die Fangliste des innersten Versuchsblocks. Wenn das System einen Catch-Block findet, der die Art von Ausnahme behandelt, springt die Programmsteuerung zu diesem Catch-Block . Wenn die Catch-Liste keinen Block enthält, der die Ausnahme angibt, übergibt das System die Ausnahme an die Catch-Liste des nächstinnersten try-Blocks . Das System verarbeitet die Catch-Anweisungen in derselben Reihenfolge, in der sie im Code erscheinen.
Es ist eine gängige Praxis, dass die erste catch-Anweisung den Exception::Error-Enumerationswert behandelt. Eine Strategie besteht darin, dass die letzte catch-Anweisung den Ausnahmetyp nicht spezifiziert. In diesem Fall behandelt die letzte catch-Anweisung alle Ausnahmen, die nicht von einer früheren catch-Anweisung behandelt werden. Diese Strategie eignet sich für den äußersten Versuch... Blöcke fangen .
Du kannst eine optionale Abschlussklausel in Versuch einbauen... Fangaussagen . Die Semantik einer finally-Klausel ist die gleiche wie in C#. Das System führt die Anweisungen in der Schlussklausel aus, wenn Control den Try-Block verlässt, entweder normal oder durch eine Ausnahme.
Die retry-Anweisung kann nur in einem catch-Block angezeigt werden. Die retry-Anweisung bewirkt, dass das Steuerelement bis zur ersten Codezeile im zugeordneten try-Block springt. Verwenden Sie die Retry-Anweisung , wenn die Ursache der Ausnahme durch den Code im Catch-Block behoben werden kann. Die retry-Anweisung gibt dem Code im try-Block eine weitere Möglichkeit, erfolgreich zu sein. Die retry-Anweisung löscht alle Meldungen, die seit dem Eintritt der Programmsteuerung in den try-Block in das Infolog geschrieben wurden.
Hinweis
Sie müssen sicherstellen, dass Ihre Wiederholungsanweisungen keine Endlosschleife verursachen. Als bewährte Methode sollte der try-Block eine Variable enthalten, die Sie testen können, um herauszufinden, ob Sie sich in einer Schleife befinden.
try
{
// Code here.
}
catch (Exception::Numeric)
{
info("Caught a Numeric exception.");
}
catch
{
info("Caught an exception.");
}
finally
{
// Executed no matter how the try block exits.
}
Der Ausnahmehandler des Systems
Wenn keine Catch-Instruktion die Ausnahme behandelt, übernimmt der System-Exception Handler sie. Der Ausnahmehandler des Systems schreibt nicht in das Infolog. Daher können nicht behandelte Ausnahmen schwer zu diagnostizieren sein. Befolgen Sie all diese Richtlinien, um eine effektive Behandlung von Ausnahmen zu gewährleisten:
- Verfügen Sie über einen try-Block , der alle Ihre Anweisungen im äußersten Frame in der Aufrufliste enthält.
- Haben Sie einen unqualifizierten Fangblock am Ende Ihrer äußersten Fangliste .
- Vermeiden Sie das direkte Auslösen eines Exception-Enumerationswerts .
- Werfen Sie den Enum-Wert ein, den eine der folgenden Methoden auf der Global-Klasse zurückgibt: Global::error, Global::warning oder Global::info. (Sie können das implizite Präfix Global:: weglassen).
- Wenn du eine Ausnahme erfährst, die im Infolog nicht angezeigt wird, rufe die Funktion Global::info auf, um sie anzuzeigen.
Ausnahme::CLRError, Exception::UpdateConflictNotRecovered und Systemkernel-Ausnahmen sind Beispiele für Ausnahmen, die das Infolog nicht automatisch anzeigt.
Ausnahmen und CLR-Interop
Sie können Microsoft .NET Framework-Klassen und -Methoden aufrufen, die in Assemblies liegen, die von der Common Language Runtime (CLR) verwaltet werden. Wenn Ihr Code eine .NET Framework System.Exception Instanz auslöst, können Sie sie fangen, indem Sie eine Variable vom Typ System.Exception deklarieren, um jede .NET-Ausnahme zu fangen, oder Sie können einen bestimmten .NET-Ausnahmetyp mit einer ihrer abgeleiteten Klassen fangen, wie im folgenden Beispiel gezeigt.
System.ArgumentException ex;
try
{
throw new System.ArgumentException("Invalid argument specified");
}
catch(ex) // Will catch the System.ArgumentException, given the type of ex.
{
error(ex.Message);
}
Sie können .NET-Ausnahmen erkennen, indem Sie auf Exception::CLRError verweisen. Ihr Code kann eine Referenz auf die System.Exception-Instanz erhalten, indem Sie die Methode CLRInterop::getLastException aufrufen.
try
{
// call to .NET code which throws exception
}
catch(Exception::CLRError)
{
System.Exception ex = CLRInterop::getLastException();
error(ex.Message);
}
Sicherstellen, dass Ausnahmen angezeigt werden
Das Infolog zeigt keine Ausnahmen des Typs Exception::CLRError an, da diese Ausnahmen nicht durch einen Aufruf einer Methode wie Global::error erzeugt werden. In Ihrem catch-Block kann Ihr Code Global::error aufrufen, um die spezifische Ausnahme zu melden.
Methoden der globalen Klasse
In diesem Abschnitt werden einige Methoden der Global-Klasse ausführlicher beschrieben. Zu diesen Klassenmethoden gehören Global::error, Global::info und Global::exceptionTextFallThrough.
Global::error-Methode
Der folgende Code zeigt, wie die Fehlermethode deklariert wird.
static Exception error
(SysInfoLogStr txt,
URL helpURL = '',
SysInfoAction _sysInfoAction = null)
Der Rückgabetyp ist der Exception:: Error-Enumerationswert. Die error-Methode löst keine Ausnahme aus. Es liefert einfach einen Enum-Wert, den du in einer Throw-Statement verwenden kannst. Die throw-Anweisung löst die Ausnahme aus. Im Folgenden finden Sie Beschreibungen der Parameter für die Fehlermethode . Es wird nur der erste Parameter benötigt.
- SysInfoLogStr txt ist ein str des Meldungstextes. Es kann sich auch um einen Beschriftungsverweis handeln, z. B. strFmt("@SYS12345", strThingName).
- Die URL helpUrl ist ein Verweis auf den Speicherort eines Hilfeartikels im Anwendungs-Explorer, z. B. "KernDoc:\\\\Functions\\substr". Der Parameterwert wird ignoriert, wenn _sysInfoAction angegeben wird.
- Die SysInfoAction ist eine Instanz einer Klasse, die die SysInfoAction-Klasse erweitert. Bei den Methodenüberschreibungen, die für die untergeordnete Klasse empfohlen werden, handelt es sich um die description-Methode , die run-Methode , die pack-Methode und die unpack-Methode .
Global::info-Methode
Verwenden Sie die Global::info-Methode , um Text im Infolog anzuzeigen. In Programmen schreibe es als info ("Meine Nachricht.");. Obwohl die Info-Methode einen Wert Exception::Info Enum zurückgibt, möchtest du Exception::Info selten verwenden, weil nichts Unerwartetes passiert ist.
Global::exceptionTextFallThrough-Methode
Gelegentlich möchten Sie innerhalb Ihres Catch-Blocks nichts tun. Der X++-Compiler generiert jedoch eine Warnung, wenn Sie über einen leeren catch-Block verfügen. Um diese Warnung zu vermeiden, rufen Sie die Global::exceptionTextFallThrough-Methode im catch-Block auf. Die Methode führt keine Aktionen aus, aber sie stellt den Compiler zufrieden und gibt die Absicht explizit an.
Ausnahmen innerhalb von Transaktionen
Wenn eine Ausnahme innerhalb einer Transaktion ausgelöst wird, wird die Transaktion automatisch abgebrochen (d. h., es tritt ein ttsAbort-Vorgang auf). Dieses Verhalten gilt sowohl für Ausnahmen, die manuell ausgelöst werden, als auch für Ausnahmen, die das System auslöst. Wenn eine Ausnahme innerhalb eines ttsBegin-ttsCommit-Transaktionsblocks- ausgelöst wird, kann keine catch-Anweisung innerhalb dieses Transaktionsblocks die Ausnahme verarbeiten (es sei denn, es handelt sich um einen UpdateConflict oder eine DuplicateKeyException). Stattdessen sind die innersten catch-Anweisungen, die sich außerhalb des Transaktionsblocks befinden, die ersten catch-Anweisungen, die getestet werden.
Um UpdateConflict oder DuplicateKeyException innerhalb einer Transaktion zu fangen, spezifizieren Sie die Ausnahme explizit in der catch-Anweisung wie diese: catch (Exception::DuplicateKeyException). Eine allgemeine Catch-All-Anweisungcatch{} kann UpdateConflict oder DuplicateKeyException innerhalb einer Transaktion nicht abfangen.
Die finally-Klausel wird auch im Transaktionsbereich ausgeführt.
Ausnahmen und using Erklärungen
Der Ausnahmebereich beeinflusst nicht die Semantik von using Aussagen. Die Aussage using :
using (var athing = new SomethingDisposable())
{
// Do work.
}
Semantisch identisch ist mit:
var athing = new SomethingDisposable();
try
{
// Do work.
}
finally
{
if (athing != null)
athing.Dispose();
}
Beispiele für die Ausnahmebehandlung
Exceptions im Infolog anzeigen
Das folgende Codebeispiel zeigt Ausnahmen im Infolog.
// This example shows that a direct throw of Exception::Error does not
// display a message in the Infolog. This is why we recommend the
// Global::error method.
static void TryCatchThrowError1Job(Args _args)
{
/***
The 'throw' does not directly add a message to the Infolog.
The exception is caught.
***/
try
{
info("In the 'try' block. (j1)");
throw Exception::Error;
}
catch (Exception::Error)
{
info("Caught 'Exception::Error'.");
}
/********** Actual Infolog output
Message (03:43:45 pm)
In the 'try' block. (j1)
Caught 'Exception::Error'.
**********/
}
Verwenden der error-Methode zum Schreiben von Ausnahmeinformationen in das Infolog
Im folgenden Codebeispiel wird die error-Methode verwendet, um Ausnahmeinformationen in das Infolog zu schreiben.
// This example shows that the use of the Global::error method
// is a reliable way to display exceptions in the Infolog.
static void TryCatchGlobalError2Job(Args _args)
{
/***
The 'Global::error()' does directly add a message to the Infolog.
The exception is caught.
***/
try
{
info("In the 'try' block. (j2)");
throw Global::error("Written to the Infolog.");
}
catch (Exception::Error)
{
info("Caught 'Exception::Error'.");
}
/*** Infolog output
Message (03:51:44 pm)
In the 'try' block. (j2)
Written to the Infolog.
Caught 'Exception::Error'.
***/
}
Umgang mit einem CLRError
Im folgenden Codebeispiel wird eine CLRError-Ausnahme behandelt.
// This example shows that a CLRError exception is not displayed
// in the Infolog unless you catch the exception and manually
// call the info method. The use of the CLRInterop::getLastException
// method is also demonstrated.
static void TryCatchCauseCLRError3Job(Args _args)
{
/***
The 'netString.Substring(-2)' causes a CLRError,
but it does not directly add a message to the Infolog.
The exception is caught.
***/
System.String netString = "Net string.";
System.Exception netExcepn;
try
{
info("In the 'try' block. (j3)");
netString.Substring(-2); // Causes CLR Exception.
}
catch (Exception::Error)
{
info("Caught 'Exception::Error'.");
}
catch (Exception::CLRError)
{
info("Caught 'Exception::CLRError'.");
netExcepn = CLRInterop::getLastException();
info(netExcepn.ToString());
}
/********** Actual Infolog output (truncated for display)
Message (03:55:10 pm)
In the 'try' block. (j3)
Caught 'Exception::CLRError'.
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. --->
System.ArgumentOutOfRangeException: StartIndex cannot be less than zero.
Parameter name: startIndex
at System.String.InternalSubStringWithChecks(Int32 startIndex, Int32 length, Boolean fAlwaysCopy)
at System.String.Substring(Int32 startIndex)
at ClrBridgeImpl.InvokeClrInstanceMethod(ClrBridgeImpl* , ObjectWrapper* objectWrapper, Char* pszMethodName,
Int32 argsLength, ObjectWrapper** arguments, Boolean* argsAreByRef, Boolean* isException)
**********/
}
Verwenden einer retry-Anweisung
Im folgenden Codebeispiel wird eine retry-Anweisung verwendet.
// This example shows how to use the retry statement. The print
// statements are included because retry causes earlier Infolog
// messages to be erased.
static void TryCatchRetry4Job(Args _args)
{
/***
Demonstration of 'retry'. The Infolog output is partially erased
by 'retry', but the Print window is fully displayed.
***/
Exception excepnEnum;
int nCounter = 0;
try
{
info(" .");
print(" .");
info("In the 'try' block, [" + int2str(nCounter) + "]. (j4)");
print("In the 'try' block, [" + int2str(nCounter) + "]. (j4)");
nCounter++;
if (nCounter >= 3) // Prevent infinite loop.
{
info("---- Will now throw a warning, which is not caught.");
print("---- Will now throw a warning, which is not caught.");
throw Global::warning("This warning will not be caught. [" + int2str(nCounter) + "]");
}
else
{
info("Did not throw a warning this loop. [" + int2str(nCounter) + "]");
print("Did not throw a warning this loop. [" + int2str(nCounter) + "]");
}
excepnEnum = Global::error("This error message is written to the Infolog.");
throw excepnEnum;
}
catch (Exception::Error)
{
info("Caught 'Exception::Error'.");
print("Caught 'Exception::Error'.");
retry;
}
info("End of job.");
print("End of job.");
/********** Actual Infolog output
Message (04:33:56 pm)
.
In the 'try' block, [2]. (j4)
---- Will now throw a warning, which is not caught.
This warning will not be caught. [3]
**********/
}
Auslösen einer Ausnahme innerhalb einer Transaktion
Im folgenden Codebeispiel wird eine Ausnahme in einem Transaktionsblock ausgelöst.
// This examples uses three levels of try nesting to illustrate
// where an exception is caught when the exception is thrown inside
// a ttsBegin ... ttsCommit transaction block.
static void TryCatchTransaction5Job(Args _args)
{
/***
Shows an exception that is thrown inside a ttsBegin - ttsCommit
transaction block cannot be caught inside that block.
***/
try
{
try
{
ttsbegin;
try
{
throw error("Throwing exception inside transaction.");
}
catch (Exception::Error)
{
info("Catch_1: Unexpected, caught in 'catch' inside the transaction block.");
}
ttscommit;
}
catch (Exception::Error)
{
info("Catch_2: Expected, caught in the innermost 'catch' that is outside of the transaction block.");
}
}
catch (Exception::Error)
{
info("Catch_3: Unexpected, caught in 'catch' far outside the transaction block.");
}
info("End of job.");
/********** Actual Infolog output
Message (04:12:34 pm)
Throwing exception inside transaction.
Catch_2: Expected, caught in the innermost 'catch' that is outside of the transaction block.
End of job.
**********/
}
Verwenden von Global::error mit einem SysInfoAction-Parameter
Wenn der Code eine Ausnahme auslöst, kann er Meldungen in das Infolog schreiben. Sie können diese Infolog-Meldungen hilfreicher gestalten, indem Sie die SysInfoAction-Klasse verwenden.
Im folgenden Beispiel übergeben Sie einen SysInfoAction-Parameter an die Global::error-Methode . Die Fehlermethode schreibt die Meldung in das Infolog. Wenn der Benutzer doppelt auf die Infolog-Nachricht klickt, wird die Methode SysInfoAction.run ausgeführt.
In der run-Methode können Sie Code schreiben, mit dem das Problem, das die Ausnahme verursacht hat, diagnostiziert oder behoben werden kann. Das Objekt, das du an die Global::error-Methode übergibst, wird aus einer Klasse konstruiert, die du schreibst und die SysInfoAction erweitert.
Das folgende Codebeispiel wird in zwei Teilen gezeigt.
- Der erste Teil zeigt einen Auftrag, der die Global::error-Methode aufruft und dann den zurückgegebenen Wert auslöst. Du übergibst eine Instanz der SysInfoAction_PrintWindow_Demo-Klasse an die Fehlermethode .
- Der zweite Teil zeigt die SysInfoAction_PrintWindow_Demo Klasse.
Teil 1: Aufrufen von Global::error
static void Job_SysInfoAction(Args _args)
{
try
{
throw Global::error
("Click me to make the Print window display."
,""
,new SysInfoAction_PrintWindow_Demo()
);
}
catch
{
warning("Issuing a warning from the catch block.");
}
}
Teil 2: Die SysInfoAction_PrintWindow_Demo Klasse
public class SysInfoAction_PrintWindow_Demo extends SysInfoAction
{
str m_sGreeting; // In classDeclaration.
public str description()
{
return "Starts the Print Window for demonstration.";
}
public void run()
{
print("This appears in the Print window.");
print(m_sGreeting);
/*********** Actual Infolog output
Message (03:19:28 pm)
Click me to make the Print window display.
Issuing a warning from the catch block.
***************/
}
public container pack()
{
return ["Packed greeting."]; // Literal container.
}
public boolean unpack(container packedClass, Object object = null)
{
[m_sGreeting] = packedClass;
return true;
}
}
Liste der Ausnahmen
In der folgenden Tabelle sind die Ausnahmeliterale aufgeführt, bei denen es sich um die Werte der Exception-Enumeration handelt.
| Ausnahme-Literal | Beschreibung |
|---|---|
| Brechen | Der Benutzer hat die Eingabetaste oder STRG+C gedrückt. |
| CLRError | Bei der Verwendung der CLR-Funktionalität ist ein Fehler aufgetreten. |
| CodeAccessSicherheit | Bei der Verwendung der CodeAccessPermission.demand-Methode ist ein Fehler aufgetreten. |
| DDEfehler | Bei der Verwendung der DDE-Systemklasse ist ein Fehler aufgetreten. |
| Blockierung | Es ist ein Datenbank-Deadlock aufgetreten, da mehrere Transaktionen aufeinander warten. |
| DuplicateKeyException | In einer Transaktion, die die Steuerung der optimistischen Parallelität verwendet, ist ein Fehler aufgetreten. Die Transaktion kann wiederholt werden (verwenden Sie eine retry-Anweisungim catch-Block ). |
| DuplicateKeyExceptionNotRecovered | In einer Transaktion, die die Steuerung der optimistischen Parallelität verwendet, ist ein Fehler aufgetreten. Der Code wird nicht wiederholt. Diese Ausnahme kann nicht in einer Transaktion abgefangen werden. |
| Fehler | Es ist ein schwerwiegender Fehler aufgetreten. Die Transaktion wurde gestoppt. |
| Info | Dieses Ausnahmeliteral enthält eine Nachricht für den Benutzer. Lösen Sie keine Info-Ausnahme aus. |
| Intern | Im Entwicklungssystem ist ein interner Fehler aufgetreten. |
| Numerisch | Bei der Verwendung der Funktionen str2int, str2int64 oder str2num ist ein Fehler aufgetreten. |
| Reihenfolge | |
| UpdateConflict (Aktualisieren) | In einer Transaktion, die die Steuerung der optimistischen Parallelität verwendet, ist ein Fehler aufgetreten. Die Transaktion kann wiederholt werden (verwenden Sie eine retry-Anweisungim catch-Block ). |
| UpdateConflictNotRecovered | In einer Transaktion, die die Steuerung der optimistischen Parallelität verwendet, ist ein Fehler aufgetreten. Der Code wird nicht wiederholt. Diese Ausnahme kann innerhalb einer Transaktion nicht abgefangen werden. |
| Warnung | Es hat sich ein außergewöhnliches Ereignis ereignet. Obwohl der Benutzer möglicherweise Maßnahmen ergreifen muss, ist das Ereignis nicht schwerwiegend. Lösen Sie keine Warnungsausnahme aus. |
| SQL-Verbindungsfehler X++-Ausnahme | Während der Ausführung der Abfrage ist ein Fehler aufgetreten. Die Transaktion wird storniert. Diese Ausnahme kann innerhalb einer Transaktion nicht abgefangen werden. |
| Zeitüberschreitung | Zeitüberschreitung bei der Ausführung von SQL-Abfragen. Die Ausnahme kann nicht innerhalb einer Transaktion abgefangen werden. Die Ausnahme kann mit einer retry-Anweisung im catch-Block wiederholt werden. |