Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of mappen te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen om mappen te wijzigen.
Notitie
Belangengroepen uit de gemeenschap zijn nu overgestapt van Yammer naar Microsoft Viva Engage. Om lid te worden van een Viva Engage community en deel te nemen aan de laatste discussies, vul je het formulier Request access to Finance and Operations Viva Engage Community in en kies de community waar je lid van wilt worden.
In dit artikel wordt de afhandeling van uitzonderingen in X++ beschreven. Fouten behandelen met de worp, probeer... Catch en retry statements om uitzonderingen te genereren en te behandelen.
Een uitzondering is een gereguleerde sprong weg van de volgorde van programma-uitvoering. De try...catch blokken en het type uitzondering dat wordt gegooid bepalen de instructie waarbij de programma-uitvoering wordt hervat. Een uitzondering wordt weergegeven door een waarde van de opsomming van uitzonderingen , of een instantie van . De klasse van System.Exception NET of een klasse die daarvan is afgeleid. Een uitzondering die je vaak gebruikt is de Exception::error enum-waarde. Een veelgebruikte praktijk is om diagnostische informatie in de Infolog te schrijven voordat de uitzondering wordt gegooid.
De Global::error methode is vaak de beste manier om diagnostische informatie naar de Infolog te schrijven. Uw methode kan bijvoorbeeld een invoerparameterwaarde ontvangen die niet geldig is. In dit geval kan de methode een uitzondering genereren om de besturing onmiddellijk over te dragen aan een catch-codeblok dat logica bevat voor het afhandelen van deze foutsituatie. Je hoeft niet per se de locatie te weten van het vangblok dat de controle krijgt wanneer de uitzondering wordt gegooid.
Gooi verklaringen
Gebruik het throw-sleutelwoord om een Exception enum-waarde te gooien. De volgende instructie genereert bijvoorbeeld een foutuitzondering.
throw Exception::error;
In plaats van een enumwaarde te gooien, gebruik je de output van de Global::error-methode als operand voor throw.
throw Global::error('The parameter value is invalid.');
De Global::error-methode kan een label automatisch omzetten in de bijbehorende tekst. Deze functionaliteit helpt u bij het schrijven van code die gemakkelijker kan worden gelokaliseerd.
throw Global::error("@SYS98765");
Je kunt de statische methoden op de Global-klasse aanroepen zonder het Global::- voorvoegsel. Je kunt bijvoorbeeld de Global::error-methode aanroepen zoals volgt.
error('My message.');
Gebruik het throw-sleutelwoord om .NET-uitzonderingen te gooien, evenals de waarden van het opgesomde Exception-type.
throw new System.InvalidOperationException("This function is not allowed");
Gebruik het worp-sleutelwoord alleen binnen een vangblok. In dit geval gedraagt throw zich als de rethrow-verklaring in C#. Het oorspronkelijke uitzonderingsbericht, uitzonderingsbericht en de context daarvan, zoals de call stack, worden opnieuw gegooid en beschikbaar voor alle catch-statements in aanroepende code.
try
{
throw Exception::error;
}
catch
{
// locally handle exception
// then rethrow for caller
throw;
}
Try, Catch, Final en Retry statements
Wanneer een uitzondering optreedt, verwerkt het systeem deze eerst via de vanglijst van het binnenste tryblok . Als het systeem een catchblok vindt dat het soort uitzondering afhandelt dat is opgetreden, springt de programmacontrole naar dat vangblok . Als de vangstlijst geen blok bevat dat de uitzondering specificeert, geeft het systeem de uitzondering door aan de vangstlijst van het volgende binnenste try-blok . Het systeem verwerkt de catch-statements in dezelfde volgorde als waarin ze in de code voorkomen.
Het is gebruikelijk om de eerste catch statement de Exception::Error enum waarde te laten afhandelen. Een strategie is om de laatste vangstverklaring het uitzonderingstype niet gespecificeerd te laten. In dit geval worden in de laatste vangstverklaring alle uitzonderingen behandeld die niet worden afgehandeld door een eerdere vangstverklaring . Deze strategie is geschikt voor de uiterste poging... Vang blokken.
Je kunt een optionele slotclausule opnemen in probeer...Vang uitspraken. De semantiek van een eindzin is hetzelfde als in C#. Het systeem voert de statements in de finally clause uit wanneer control het try-blok verlaat, hetzij normaal of via een uitzondering.
De instructie voor een nieuwe poging kan alleen in een catch block worden weergegeven. De instructie voor opnieuw proberen zorgt ervoor dat de besturing omhoog springt naar de eerste regel code in het bijbehorende try-blok . Gebruik de retry-instructie wanneer de oorzaak van de uitzondering kan worden opgelost door de code in het catch-blok . De instructie voor opnieuw proberen geeft de code in het try-blok nog een kans om te slagen. Met de retry-instructie worden alle berichten gewist die naar de Infolog zijn geschreven sinds het programmabesturingselement het try-blok is binnengegaan.
Notitie
U moet ervoor zorgen dat uw retry-instructies geen oneindige lus veroorzaken. Als best practice moet het try-blok een variabele bevatten die je kunt testen om erachter te komen of je in een lus zit.
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.
}
De handler voor systeemuitzonderingen
Als geen catch-instructie de uitzondering afhandelt, behandelt de systeem-exceptionhandler deze dan. De handler voor systeemuitzonderingen schrijft niet naar het infologboek. Daarom kunnen onverwerkte uitzonderingen moeilijk te diagnosticeren zijn. Volg al deze richtlijnen om effectieve afhandeling van uitzonderingen te garanderen:
- Zorg voor een probeerblok dat al uw instructies bevat in het buitenste frame van de aanroepstapel.
- Zorg voor een ongekwalificeerd vangstblok aan het einde van je buitenste vangstlijst .
- Vermijd het rechtstreeks genereren van een Exception enum-waarde.
- Gooi de enumwaarde die een van de volgende methoden op de Global-klasse teruggeeft: Global::error, Global::warning, of Global::info. (U kunt het impliciete voorvoegsel Global:: weglaten).
- Wanneer je een uitzondering ziet die de Infolog niet toont, roep dan de Global::info-functie aan om deze te tonen.
Uitzondering::CLRError, Exception::UpdateConflictNotRecovered en systeemkernel-uitzonderingen zijn voorbeelden van uitzonderingen die de Infolog niet automatisch toont.
Uitzonderingen en CLR-interoperabiliteit
Je kunt Microsoft .NET Framework-klassen en -methoden aanroepen die zich bevinden in assemblies die door de common language runtime (CLR) worden beheerd. Wanneer je code een .NET Framework System.Exception-instantie gooit, kun je deze vangen door een variabele van het type System.Exception te declareren om elke .NET-exception te vangen, of je kunt een specifiek .NET-exceptiontype vangen door een van de afgeleide klassen te gebruiken, zoals in het volgende voorbeeld te zien is.
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);
}
Je kunt .NET-uitzonderingen vangen door te verwijzen naar Exception::CLRError. Je code kan een referentie naar de System.Exception-instantie krijgen door de methode CLRInterop::getLastException aan te roepen.
try
{
// call to .NET code which throws exception
}
catch(Exception::CLRError)
{
System.Exception ex = CLRInterop::getLastException();
error(ex.Message);
}
Ervoor zorgen dat uitzonderingen worden getoond
De Infolog toont geen uitzonderingen van het type Exception::CLRError , omdat deze uitzonderingen niet worden gegenereerd door een aanroep naar een methode zoals Global::error. In uw catch block kan uw code Global::error aanroepen om de specifieke uitzondering te rapporteren.
Wereldwijde klasmethoden
In dit gedeelte worden enkele methoden voor wereldwijde klassen in meer detail beschreven. Deze klassemethoden omvatten Global::error, Global::info en Global::exceptionTextFallThrough.
Global::error methode
De volgende code geeft aan hoe de foutmethode wordt gedeclareerd.
static Exception error
(SysInfoLogStr txt,
URL helpURL = '',
SysInfoAction _sysInfoAction = null)
Het retourtype is de Exception::Error enum-waarde. De foutmethode genereert geen uitzondering. Het geeft gewoon een enumwaarde die je kunt gebruiken in een throw-statement . De werpverklaring gooit de uitzondering. Hier vindt u beschrijvingen van de parameters voor de foutmethode . Alleen de eerste parameter is vereist.
- SysInfoLogStr txt is een str van de berichttekst. Het kan ook een labelverwijzing zijn, zoals strFmt("@SYS12345", strThingName).
- De URL helpUrl is een verwijzing naar de locatie van een Help-artikel in Application Explorer, zoals "KernDoc:\\\\Functions\\substr". De parameterwaarde wordt genegeerd als _sysInfoAction wordt opgegeven.
- De SysInfoAction is een instantie van een klasse die de klasse SysInfoAction uitbreidt. De methode-overschrijven die we aanbevelen voor de onderliggende klasse zijn de beschrijvingsmethode , de uitvoeringsmethode , de inpakmethode en de uitpakmethode .
Global::info methode
Gebruik de Global::info-methode om tekst in de Infolog te tonen. In programma's schrijf je het als info ("Mijn bericht.");. Hoewel de info-methode een Exception::Info enum-waarde teruggeeft, wil je zelden Exception::Info gebruiken, omdat er niets onverwachts is gebeurd.
Global::exceptionTextFallThrough methode
Af en toe wil je niets doen in je vangblok . De X++ compiler genereert echter een waarschuwing als je een leeg catch block hebt. Als u deze waarschuwing wilt voorkomen, roept u de methode Global::exceptionTextFallThrough aan in het catch block. De methode doet niets, maar het voldoet aan de compiler en geeft expliciet de intentie aan.
Uitzonderingen binnen transacties
Als er een uitzondering in een transactie wordt gegenereerd, wordt de transactie automatisch geannuleerd (dat wil zeggen dat er een ttsAbort-bewerking plaatsvindt). Dit gedrag is van toepassing op zowel uitzonderingen die handmatig worden gegenereerd als uitzonderingen die door het systeem worden gegenereerd. Wanneer een uitzondering in een ttsBegin-ttsCommitt-transactieblok wordt gegooid, kan geen enkele catch statement in dat transactieblok de uitzondering verwerken (tenzij het een UpdateConflict of een DuplicateKeyException is). In plaats daarvan zijn de binnenste catch statements die buiten het transactieblok vallen de eerste catch statements die worden getest.
Om UpdateConflict of DuplicateKeyException binnen een transactie te vangen, specificeer expliciet de uitzondering in de catch-instructie zoals volgt, catch (Exception::DuplicateKeyException). Een algemene catch-all-instructiecatch{} kan geen UpdateConflict of DuplicateKeyException in een transactie vangen.
De uiteindelijke clausule wordt zelfs in de reikwijdte van de transactie uitgevoerd.
Uitzonderingen en using verklaringen
Uitzonderingsscope heeft geen invloed op de semantiek van using statements. De using verklaring:
using (var athing = new SomethingDisposable())
{
// Do work.
}
Is semantisch identiek aan:
var athing = new SomethingDisposable();
try
{
// Do work.
}
finally
{
if (athing != null)
athing.Dispose();
}
Voorbeelden van afhandeling van uitzonderingen
Uitzonderingen weergeven in het infologboek
In het volgende codevoorbeeld ziet u uitzonderingen in het infologboek.
// 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'.
**********/
}
De foutmethode gebruiken om uitzonderingsinformatie naar het infologboek te schrijven
In het volgende codevoorbeeld wordt de foutmethode gebruikt om uitzonderingsinformatie naar het infologboek te schrijven.
// 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'.
***/
}
Omgaan met een CLRError
In het volgende codevoorbeeld wordt een CLRErlor-uitzondering behandeld.
// 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)
**********/
}
Een instructie voor opnieuw proberen gebruiken
In het volgende codevoorbeeld wordt een instructie voor opnieuw proberen gebruikt.
// 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]
**********/
}
Een uitzondering in een transactie gooien
In het volgende codevoorbeeld wordt een uitzondering in een transactieblok gegenereerd.
// 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.
**********/
}
Global::error gebruiken met een SysInfoAction-parameter
Wanneer uw code een uitzondering genereert, kan deze berichten naar de Infolog schrijven. U kunt deze Infolog-berichten nuttiger maken met behulp van de klasse SysInfoAction .
In het volgende voorbeeld geef je een SysInfoAction-parameter door aan de Global::error-methode . De foutmethode schrijft het bericht naar het infologboek. Wanneer de gebruiker dubbelklikt op het Infolog-bericht, draait de SysInfoAction.run-methode .
In de uitvoeringsmethode kunt u code schrijven die helpt bij het diagnosticeren of oplossen van het probleem dat de uitzondering heeft veroorzaakt. Het object dat je doorgeeft aan de Global::error-methode is opgebouwd uit een klasse die je schrijft en die SysInfoAction uitbreidt.
Het volgende codevoorbeeld wordt in twee delen weergegeven.
- In het eerste deel ziet u een taak die de methode Global::error aanroept en vervolgens de geretourneerde waarde genereert. Je geeft een instantie van de SysInfoAction_PrintWindow_Demo klasse door aan de foutmethode .
- Het tweede deel toont de SysInfoAction_PrintWindow_Demo klas.
Deel 1: Calling 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.");
}
}
Deel 2: De SysInfoAction_PrintWindow_Demo klas
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;
}
}
Lijst met uitzonderingen
In de volgende tabel ziet u de letterlijke waarden van de uitzondering die de waarden zijn van de opsomming van uitzonderingen.
| Uitzondering letterlijk | Beschrijving |
|---|---|
| Breken | De gebruiker heeft op Break of Ctrl+C gedrukt. |
| CLRError | Er is een fout opgetreden tijdens het gebruik van de CLR-functionaliteit. |
| CodeAccessBeveiliging | Er is een fout opgetreden terwijl de methode CodeAccessPermission.demand werd gebruikt. |
| DDEfout | Er is een fout opgetreden terwijl de DDE-systeemklasse werd gebruikt. |
| Patstelling | Er is een database deadlock ontstaan, omdat er meerdere transacties op elkaar wachten. |
| DuplicateKeyException | Er is een fout opgetreden in een transactie die gebruikmaakt van Optimistic Concurrency Control. De transactie kan opnieuw worden geprobeerd (gebruik een retry-instructie in het catch block). |
| DuplicateKeyExceptionNotRecovered | Er is een fout opgetreden in een transactie die gebruikmaakt van Optimistic Concurrency Control. De code wordt niet opnieuw geprobeerd. Deze uitzondering kan niet worden vastgelegd in een transactie. |
| Fout | Er is een fatale fout opgetreden. De transactie is stopgezet. |
| Info | Deze uitzondering bevat letterlijk een bericht voor de gebruiker. Gooi geen info-uitzondering . |
| Intern | Er is een interne fout opgetreden in het ontwikkelsysteem. |
| Numeriek | Er is een fout opgetreden terwijl de functie str2int, str2int64 of str2num werd gebruikt. |
| Volgorde | |
| Conflict bijwerken | Er is een fout opgetreden in een transactie die gebruikmaakt van Optimistic Concurrency Control. De transactie kan opnieuw worden geprobeerd (gebruik een retry-instructie in het catch block). |
| UpdateConflictNotRecovered | Er is een fout opgetreden in een transactie die gebruikmaakt van Optimistic Concurrency Control. De code wordt niet opnieuw geprobeerd. Deze uitzondering kan niet worden gevangen in een transactie. |
| Waarschuwing | Er heeft zich een uitzonderlijke gebeurtenis voorgedaan. Hoewel de gebruiker misschien actie moet ondernemen, is de gebeurtenis niet fataal. Gooi geen waarschuwingsuitzondering . |
| SQL-verbindingsfout X++ uitzondering | Er is een fout opgetreden tijdens de uitvoering van de query. De transactie wordt geannuleerd. Deze uitzondering kan niet worden gevangen in een transactie. |
| Timeout | Er is een time-out opgetreden voor de uitvoering van SQL-query's. De uitzondering kan niet worden gevangen in een transactie. De uitzondering kan opnieuw worden geprobeerd met behulp van een retry-instructie in het catch block. |