This
article describes the exception handling in X++. we can handle errors by using
the below key statements or keywords in the X++ code.
- throw
- try
- catch
- finally
- retry
throw statements
We
use the throw keyword to throw an Exception. throw
statement can be used to either to throw generic error message or a custom
error message. For example, the following statement throws an error
exception.
throw Exception::error;
Instead
of throwing an enum value, the below example shows the throw with a custom
error message. The best practice is to use the output of the Global::error method
as the operand for throw.
throw error("Error
thrown."); //The Hard coded values can also be replaced with labels
created.
try, catch, finally, and retry statements
When an exception is thrown, it's first
processed through the catch list of the innermost try block.
If a catch block is found that handles the kind of exception
that is being thrown, program control jumps to that catch block.
If the catch list has no block that specifies the exception,
the system passes the exception to the catch list of the
next-innermost try block. The catch statements
are processed in the same sequence as they appear in the code.
It's
a common practice to have the first catch statement handle
the Exception::Error enum value. One strategy is to have the
last catch statement leave the exception type unspecified. In
this case, the last catch statement handles all exceptions
that aren't handled by any earlier catch statement. This
strategy is appropriate for the outermost try...catch blocks.
An
optional finally clause can be included in try...catch statements.
The semantics of a finally clause are the same as they are in
C#. The statements in the finally clause are executed when
control leaves the try block, either normally or through an
exception.
The retry statement
can be written only in a catch block. The retry statement
causes control to jump up to the first line of code in the associated try block.
The retry statement is used when the cause of the exception
can be fixed by the code in the catch block. The retry statement
gives the code in the try block another opportunity to succeed.
The retry statement erases all messages that have been written
to the Infolog since program control entered the try block.
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.
}
Exceptions inside transactions
If
an exception is thrown inside a transaction, the transaction is automatically
canceled (that is, a ttsAbort operation occurs). This behavior applies for both
exceptions that are thrown manually and exceptions that the system throws. When
an exception is thrown inside a ttsBegin-ttsCommit transaction block, no catch statement inside that transaction block
can process the exception, (unless it is a UpdateConflict or a DuplicateKeyException). Instead, the innermost catch statements that are outside the
transaction block are the first catch statements that are tested.
The
finally clause will be executed even in transaction scope.
Examples of exception handling
The following code
example shows 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'.
***/
}
Throwing an exception
inside a transaction
The
following code example throws an exception in a 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.
**********/
}