1. Bloques TRY-CATCH
Puntos Clave
- Bloque TRY: Contiene código protegido que puede generar errores
- Bloque CATCH: Recibe un objeto de excepción derivado de %Exception.AbstractException
- Propiedades de la excepción: ex.Name (nombre del error), ex.Code (código del error), ex.Data (datos adicionales), ex.Location (dónde ocurrió el error)
- Múltiples CATCH: Solo un bloque CATCH por TRY; usar IF/ELSEIF dentro del CATCH para manejar diferentes tipos de error
- Anidamiento: Los bloques TRY-CATCH pueden anidarse para un manejo de errores más granular
- Sin nivel de pila: Los bloques TRY no crean un nuevo nivel de pila
Notas Detalladas
Descripción General
TRY-CATCH es el mecanismo de manejo de errores recomendado en ObjectScript moderno. Proporciona un manejo de errores estructurado, legible y mantenible usando objetos de excepción que llevan información detallada sobre qué salió mal y dónde.
Sintaxis Básica de TRY-CATCH
ClassMethod BasicExample()
{
TRY {
// Protected code
Set x = 1 / 0 // Will cause <DIVIDE> error
Write "This line never executes", !
}
CATCH ex {
Write "Error: ", ex.Name, ! // <DIVIDE>
Write "Code: ", ex.Code, ! // Error code
Write "Location: ", ex.Location, ! // Where it happened
Write "Data: ", ex.Data, ! // Additional info
}
Write "Execution continues here", !
}
Propiedades y Métodos del Objeto de Excepción
La variable del CATCH es una instancia de %Exception.AbstractException (o una subclase). Propiedades y métodos clave:
ClassMethod ExamineException()
{
TRY {
Set ^ReadOnlyGlobal(1) = "test" // Assuming <PROTECT> error
}
CATCH ex {
// Properties
Write "Name: ", ex.Name, ! // Error name (e.g., <PROTECT>)
Write "Code: ", ex.Code, ! // Numeric error code
Write "Location: ", ex.Location, ! // label+offset^routine
Write "Data: ", ex.Data, ! // Context-specific data
// Methods
Write "Display: ", ex.DisplayString(), ! // Full formatted string
Set sc = ex.AsStatus() // Convert to %Status
Write "Status: ", $SYSTEM.Status.GetErrorText(sc), !
// As a SQL code
Write "SQL Code: ", ex.AsSQLCODE(), !
Write "SQL Msg: ", ex.AsSQLMessage(), !
}
}
Bloques TRY-CATCH Anidados
ClassMethod NestedExample()
{
TRY {
Write "Outer TRY", !
TRY {
Write "Inner TRY", !
// Generate an error
Set x = $PIECE("", ",", -1) // <FUNCTION> error
}
CATCH innerEx {
Write "Inner CATCH: ", innerEx.Name, !
// Can rethrow to outer CATCH
If innerEx.Name = "<SERIOUS>" {
THROW innerEx
}
// Otherwise handle it here
}
Write "Continues in outer TRY", !
}
CATCH outerEx {
Write "Outer CATCH: ", outerEx.Name, !
}
}
Manejo de Diferentes Tipos de Error Dentro del CATCH
ClassMethod HandleByType()
{
TRY {
Do ..RiskyOperation()
}
CATCH ex {
If ex.Name = "<DIVIDE>" {
Write "Division by zero detected", !
}
ElseIf ex.Name = "<UNDEFINED>" {
Write "Undefined variable: ", ex.Data, !
}
ElseIf ex.Name = "<SUBSCRIPT>" {
Write "Invalid subscript access", !
}
Else {
Write "Unexpected error: ", ex.DisplayString(), !
// Rethrow unexpected errors
THROW ex
}
}
}
Referencias de Documentación
2. Lanzamiento de excepciones
Puntos Clave
- Comando THROW: Lanza un objeto de excepción, transfiriendo el control al bloque CATCH más cercano
- %Exception.General: Clase de excepción de propósito general para errores definidos por el usuario
- $$$ThrowStatus: Macro que lanza una excepción creada a partir de un valor %Status
- $$$ThrowOnError: Macro que lanza solo si el estado es un error (no hace nada si es OK)
- Clases de excepción personalizadas: Pueden extender %Exception.AbstractException para errores específicos de la aplicación
- Relanzamiento: Capturar una excepción y hacer THROW nuevamente para propagarla a un manejador externo
Notas Detalladas
Descripción General
Lanzar excepciones permite señalar condiciones de error explícitamente, en lugar de depender solo de errores generados por el sistema. Esto es esencial para crear aplicaciones robustas con límites de error claros.
Lanzamiento de %Exception.General
ClassMethod ValidateAge(age As %Integer) As %Status
{
TRY {
If age < 0 {
Throw ##class(%Exception.General).%New(
"InvalidAge", // Name
5001, // Code (application-defined)
, // Location (auto-filled)
"Age cannot be negative: " _ age) // Data
}
If age > 150 {
Throw ##class(%Exception.General).%New(
"InvalidAge", 5001, , "Unrealistic age: " _ age)
}
Write "Age is valid: ", age, !
Return $$$OK
}
CATCH ex {
Write "Validation error: ", ex.Name, !
Write "Details: ", ex.Data, !
Return ex.AsStatus()
}
}
Uso de la Macro $$$ThrowStatus
La macro $$$ThrowStatus convierte un valor %Status en una excepción y la lanza. Esto es esencial para conectar código basado en estados con código basado en excepciones.
Include %occStatus
ClassMethod SaveRecord() As %Status
{
TRY {
Set obj = ##class(MyApp.Person).%New()
Set obj.Name = "John Doe"
Set sc = obj.%Save()
// If sc is an error, throw it as an exception
$$$ThrowOnError(sc)
Write "Saved successfully with ID: ", obj.%Id(), !
Return $$$OK
}
CATCH ex {
Write "Save failed: ", ex.DisplayString(), !
Return ex.AsStatus()
}
}
$$$ThrowOnError vs $$$ThrowStatus
Include %occStatus
ClassMethod CompareThrowMacros()
{
TRY {
Set sc = $$$OK
// $$$ThrowOnError: Only throws if sc is an error
// Does NOTHING if sc is $$$OK -- safe to use always
$$$ThrowOnError(sc) // No effect, sc is OK
Set sc = $$$ERROR($$$GeneralError, "Something went wrong")
// $$$ThrowStatus: ALWAYS throws, even if sc is OK
// Use this only when you KNOW sc is an error
// $$$ThrowStatus(sc) // Would always throw
// $$$ThrowOnError: Throws because sc is now an error
$$$ThrowOnError(sc) // This throws!
Write "Never reached", !
}
CATCH ex {
Write "Caught: ", ex.DisplayString(), !
}
}
Relanzamiento de Excepciones
ClassMethod OuterMethod()
{
TRY {
Do ..InnerMethod()
}
CATCH ex {
Write "Final handler: ", ex.DisplayString(), !
}
}
ClassMethod InnerMethod() [ Private ]
{
TRY {
// Some risky operation
Set value = $LISTGET($LISTBUILD(), 5)
}
CATCH ex {
// Log the error
Set ^ErrorLog($INCREMENT(^ErrorLog)) = ex.DisplayString()
// Rethrow to let caller handle it
THROW ex
}
}
Referencias de Documentación
3. Registro de errores de la aplicación
Puntos Clave
- Global ^ERRORS: Global del sistema que almacena errores de la aplicación automáticamente cuando ocurren errores no manejados
- $SYSTEM.OBJ.DisplayError(): Muestra texto de error legible a partir de un valor %Status
- Management Portal: Visor del registro de errores de la aplicación en System Operation > System Logs > Application Error Log
- Estructura del error: ^ERRORS almacena nombre del error, ubicación, traza de pila, variables y marca de tiempo
- ^%ERN: Global de contador que rastrea el número de errores por namespace
- Registro personalizado: La mejor práctica es complementar el registro del sistema con registros de errores específicos de la aplicación
Notas Detalladas
Descripción General
InterSystems IRIS registra automáticamente los errores no manejados en la global ^ERRORS. Además, los desarrolladores deben implementar un registro de errores estructurado dentro de sus aplicaciones para un diagnóstico completo.
La Global ^ERRORS
Cuando ocurre un error no manejado (sin TRY-CATCH ni $ZTRAP en efecto), IRIS registra el error en la global ^ERRORS en el namespace actual. La estructura contiene:
// Viewing the error log from Terminal
ZWrite ^ERRORS
// Structure of ^ERRORS:
// ^ERRORS(date, index) = errorName
// ^ERRORS(date, index, "m") = stack trace details
// where date is in $HOROLOG format and index is sequential
Registro de Errores de la Aplicación en el Management Portal
Navegar a System Operation > System Logs > Application Error Log para ver una tabla formateada de errores de la aplicación. Esta página muestra:
- Fecha y hora de cada error
- Nombre del error (por ejemplo,
<UNDEFINED>,<SUBSCRIPT>) - Ubicación donde ocurrió el error
- Namespace donde ocurrió el error
- ID del proceso y nombre de usuario
Uso de Métodos de $SYSTEM.Status para Mostrar Errores
Include %occStatus
ClassMethod DemonstrateErrorDisplay()
{
// Create an error status
Set sc = $$$ERROR($$$GeneralError, "Database connection failed")
// DisplayError - writes to current device
Do $SYSTEM.Status.DisplayError(sc)
// Output: ERROR #5001: Database connection failed
// GetErrorText - returns error as a string
Set errorText = $SYSTEM.Status.GetErrorText(sc)
Write "Error text: ", errorText, !
// For multi-status errors, get individual components
Set sc2 = $$$ERROR($$$GeneralError, "Additional problem")
Set combinedSc = $SYSTEM.Status.AppendStatus(sc, sc2)
// GetOneStatusText gets a specific error from a compound status
Set firstError = $SYSTEM.Status.GetOneStatusText(combinedSc, 1)
Set secondError = $SYSTEM.Status.GetOneStatusText(combinedSc, 2)
Write "First: ", firstError, !
Write "Second: ", secondError, !
}
Registro de Excepciones en el Registro de Errores de la Aplicación
La forma más simple de registrar una excepción capturada en ^ERRORS (visible en el Management Portal y mediante Do ^%ER) es llamar al método .Log() en el objeto de excepción:
TRY {
// Business logic
Set result = 100 / 0
}
CATCH ex {
// Log to ^ERRORS (calls LOG^%ETN internally)
Do ex.Log()
// Continue with error handling...
Return ex.AsStatus()
}
El método %Exception.AbstractException.Log() llama a LOG^%ETN para registrar la excepción en el registro de errores del sistema. Luego se pueden ver los errores registrados:
- Terminal: Utilidad
Do ^%ER - Management Portal: System Operation > System Logs > Application Error Log
Este es el enfoque recomendado para registrar excepciones capturadas, ya que las excepciones no manejadas se registran automáticamente pero las excepciones capturadas no se registran a menos que se llame explícitamente a .Log().
Construcción de un Registro de Errores Personalizado de la Aplicación
ClassMethod LogError(
className As %String,
methodName As %String,
ex As %Exception.AbstractException)
{
Set timestamp = $ZDATETIME($HOROLOG, 3)
Set key = $INCREMENT(^MyApp.ErrorLog)
Set ^MyApp.ErrorLog(key, "timestamp") = timestamp
Set ^MyApp.ErrorLog(key, "class") = className
Set ^MyApp.ErrorLog(key, "method") = methodName
Set ^MyApp.ErrorLog(key, "error") = ex.DisplayString()
Set ^MyApp.ErrorLog(key, "name") = ex.Name
Set ^MyApp.ErrorLog(key, "code") = ex.Code
Set ^MyApp.ErrorLog(key, "location") = ex.Location
Set ^MyApp.ErrorLog(key, "data") = ex.Data
// Also log the stack trace
For level = 0:1:$STACK(-1) {
Set ^MyApp.ErrorLog(key, "stack", level) =
$STACK(level, "PLACE") _ " : " _ $STACK(level, "MCODE")
}
}
ClassMethod ProcessData()
{
TRY {
// Business logic here
Set result = 100 / 0
}
CATCH ex {
Do ..LogError("MyApp.Processor", "ProcessData", ex)
// Optionally rethrow or return error status
Return ex.AsStatus()
}
}
Referencias de Documentación
4. $STACK para trazado
Puntos Clave
- $STACK(-1): Devuelve la profundidad actual de la pila (número de niveles en la pila de ejecución)
- $STACK(level, "PLACE"): Devuelve la ubicación (etiqueta+desplazamiento^rutina) en el nivel de pila especificado
- $STACK(level, "MCODE"): Devuelve el código fuente real en el nivel de pila especificado
- $STACK(level, "ECODE"): Devuelve el código de error en un nivel dado (si ocurrió un error allí)
- Patrón de bucle: Iterar de 0 a $STACK(-1) para volcar la pila de llamadas completa
- Uso diagnóstico: Esencial para comprender las cadenas de llamadas durante el manejo de errores
Notas Detalladas
Descripción General
La variable especial $STACK proporciona acceso programático a la pila de llamadas de ejecución. Durante el manejo de errores, $STACK permite capturar una traza completa de la cadena de llamadas que condujo al error, lo cual es invaluable para la depuración.
Uso Básico de $STACK
ClassMethod ShowStack()
{
Write "Current stack depth: ", $STACK(-1), !
Write !
For level = 0:1:$STACK(-1) {
Write "Level ", level, ": "
Write $STACK(level, "PLACE")
Write !
}
}
Volcado Completo de Pila Durante el Manejo de Errores
ClassMethod MethodA()
{
TRY {
Do ..MethodB()
}
CATCH ex {
Write "Error: ", ex.DisplayString(), !
Write "--- Stack Trace ---", !
Do ..DumpStack()
}
}
ClassMethod MethodB() [ Private ]
{
Do ..MethodC()
}
ClassMethod MethodC() [ Private ]
{
// Cause an error
Set x = undefinedVariable // <UNDEFINED> error
}
ClassMethod DumpStack()
{
Set depth = $STACK(-1)
Write "Stack depth: ", depth, !
For level = 0:1:depth {
Write " Level ", level, ":", !
Write " PLACE: ", $STACK(level, "PLACE"), !
Write " MCODE: ", $STACK(level, "MCODE"), !
Set ecode = $STACK(level, "ECODE")
If ecode '= "" {
Write " ECODE: ", ecode, !
}
}
}
La salida se vería así:
Error: <UNDEFINED>zMethodC+1^MyApp.Debug.1 *undefinedVariable
--- Stack Trace ---
Stack depth: 3
Level 0:
PLACE: +1^MyApp.Debug.1
MCODE: Do ..MethodB()
Level 1:
PLACE: zMethodB+1^MyApp.Debug.1
MCODE: Do ..MethodC()
Level 2:
PLACE: zMethodC+1^MyApp.Debug.1
MCODE: Set x = undefinedVariable
ECODE: <UNDEFINED>
Referencia de Parámetros de $STACK
| Sintaxis | Devuelve |
|---|---|
$STACK(-1) | Profundidad actual de la pila (entero) |
$STACK(n, "PLACE") | Ubicación en el nivel n (etiqueta+desplazamiento^rutina) |
$STACK(n, "MCODE") | Código fuente en el nivel n |
$STACK(n, "ECODE") | Código de error en el nivel n (vacío si no hay error) |
Integración de $STACK con el Registro de Errores
ClassMethod CaptureStackTrace() As %String
{
Set trace = ""
Set depth = $STACK(-1)
For level = 0:1:depth {
Set line = "Level " _ level _ ": "
Set line = line _ $STACK(level, "PLACE")
Set mcode = $STACK(level, "MCODE")
If mcode '= "" {
Set line = line _ " [" _ mcode _ "]"
}
Set trace = trace _ line _ $CHAR(10)
}
Return trace
}
ClassMethod HandleError()
{
TRY {
Do ..SomeOperation()
}
CATCH ex {
Set stackTrace = ..CaptureStackTrace()
// Store in error log global
Set key = $INCREMENT(^ErrorLog)
Set ^ErrorLog(key) = ex.DisplayString()
Set ^ErrorLog(key, "stack") = stackTrace
Set ^ErrorLog(key, "time") = $ZDATETIME($HOROLOG, 3)
}
}
Referencias de Documentación
5. Conversión de códigos de estado de error
Puntos Clave
- $$$ISERR(sc): Macro que devuelve verdadero (1) si el estado representa un error
- $$$ISOK(sc): Macro que devuelve verdadero (1) si el estado representa éxito
- $SYSTEM.Status.GetErrorText(sc): Devuelve una cadena de error legible
- $SYSTEM.Status.DisplayError(sc): Escribe el texto del error en el dispositivo actual
- $SYSTEM.Status.GetOneStatusText(sc, n): Devuelve el enésimo error de un estado compuesto
- $$$ERROR(): Macro para crear un nuevo valor %Status de error con un código de error y mensaje específicos
Notas Detalladas
Descripción General
%Status es un tipo de datos fundamental en InterSystems IRIS utilizado en toda la biblioteca de clases para indicar éxito o fallo de operaciones. Métodos como %Save(), %New(), %Open() y muchos otros devuelven valores %Status. Comprender cómo probar, mostrar y crear valores de estado es esencial.
Prueba de Valores de Estado
Include %occStatus
ClassMethod TestStatus()
{
Set obj = ##class(Sample.Person).%New()
Set obj.Name = "Test Person"
Set sc = obj.%Save()
// Test if the operation succeeded
If $$$ISOK(sc) {
Write "Save succeeded, ID: ", obj.%Id(), !
}
// Test if the operation failed
If $$$ISERR(sc) {
Write "Save failed!", !
}
// IMPORTANT: Never compare %Status directly to 1 or 0
// WRONG: If sc = 1 { ... }
// RIGHT: If $$$ISOK(sc) { ... }
}
Mostrar y Extraer Texto de Error
Include %occStatus
ClassMethod DisplayStatusExamples()
{
// Create an error status for demonstration
Set sc = $$$ERROR($$$GeneralError, "Connection timeout after 30 seconds")
// Method 1: Display to current device
Do $SYSTEM.Status.DisplayError(sc)
// Output: ERROR #5001: Connection timeout after 30 seconds
// Method 2: Get as a string (for logging, display elsewhere)
Set text = $SYSTEM.Status.GetErrorText(sc)
Write "Error: ", text, !
// Method 3: Compound status with multiple errors
Set sc1 = $$$ERROR($$$GeneralError, "First error")
Set sc2 = $$$ERROR($$$GeneralError, "Second error")
Set combined = $SYSTEM.Status.AppendStatus(sc1, sc2)
// Get individual error messages
Set first = $SYSTEM.Status.GetOneStatusText(combined, 1)
Set second = $SYSTEM.Status.GetOneStatusText(combined, 2)
Write "Error 1: ", first, !
Write "Error 2: ", second, !
// Get count of errors
Set count = $SYSTEM.Status.GetErrorCodes(combined)
Write "Total errors: ", count, !
}
Creación de Valores de Estado de Error
Include (%occStatus, %occErrors)
ClassMethod CreateErrors()
{
// General error with custom message
Set sc = $$$ERROR($$$GeneralError, "Custom error message")
// Error with specific error code
Set sc = $$$ERROR($$$InvalidArgument, "paramName")
// Compound status: append multiple errors
Set sc = $$$OK
If 'condition1 {
Set sc = $SYSTEM.Status.AppendStatus(sc,
$$$ERROR($$$GeneralError, "Condition 1 failed"))
}
If 'condition2 {
Set sc = $SYSTEM.Status.AppendStatus(sc,
$$$ERROR($$$GeneralError, "Condition 2 failed"))
}
Return sc // Contains all accumulated errors
}
Patrón Común: Verificación del Estado de Retorno
Include %occStatus
ClassMethod RobustSave() As %Status
{
Set sc = $$$OK
Set obj = ##class(MyApp.Data).%New()
Set obj.Field1 = "value1"
Set sc = obj.%Save()
If $$$ISERR(sc) {
// Log and return
Do $SYSTEM.Status.DisplayError(sc)
Return sc
}
// Continue with more operations
Set sc = ..AdditionalProcessing(obj.%Id())
If $$$ISERR(sc) Return sc
Return $$$OK
}
Referencias de Documentación
6. Estados vs excepciones
Puntos Clave
- Patrón %Status: Los métodos devuelven %Status, el llamador verifica con $$$ISERR/$$$ISOK -- usado por %Save, %New, %Open
- Patrón de excepciones: Los errores se lanzan como excepciones, capturados por TRY-CATCH -- usado para errores del sistema y THROW explícito
- $$$ThrowOnError(sc): Convierte un error %Status en una excepción (puente del mundo de estados al mundo de excepciones)
- ex.AsStatus(): Convierte una excepción de vuelta a un valor %Status (puente del mundo de excepciones al mundo de estados)
- %Exception.StatusException: Subclase de excepción creada a partir de un valor %Status
- Mezcla de patrones: Es común usar excepciones internamente pero devolver %Status a los llamadores
Notas Detalladas
Descripción General
InterSystems IRIS usa dos patrones distintos de señalización de errores: valores de retorno %Status y excepciones. El patrón %Status es ubicuo en la biblioteca de clases (por ejemplo, %Save(), %Open()), mientras que las excepciones se usan para errores en tiempo de ejecución y manejo de errores estructurado moderno. El código del mundo real debe conectar ambos patrones con fluidez.
El Patrón %Status
Include %occStatus
/// Pure %Status style - check every return value
ClassMethod StatusStyle() As %Status
{
Set sc = $$$OK
Set obj = ##class(MyApp.Person).%New()
Set obj.Name = "Test"
// %Save returns %Status
Set sc = obj.%Save()
If $$$ISERR(sc) {
Do $SYSTEM.Status.DisplayError(sc)
Return sc
}
// %OpenId returns object or "" (with status in second arg)
Set obj2 = ##class(MyApp.Person).%OpenId(999, , .sc)
If $$$ISERR(sc) {
Return sc
}
Return $$$OK
}
El Patrón de Excepciones
/// Pure exception style - everything in TRY-CATCH
ClassMethod ExceptionStyle()
{
TRY {
Set x = 100 / 0 // <DIVIDE> - system exception
Set ^data(1) = "value" // <PROTECT> - system exception
}
CATCH ex {
Write "Caught: ", ex.DisplayString(), !
}
}
Conversión de %Status a Excepción con $$$ThrowOnError
Include %occStatus
/// Recommended hybrid: Use exceptions internally, return %Status
ClassMethod RecommendedPattern() As %Status
{
TRY {
Set obj = ##class(MyApp.Person).%New()
Set obj.Name = "Test"
// %Save returns %Status -- convert to exception if error
Set sc = obj.%Save()
$$$ThrowOnError(sc)
// %OpenId with status -- convert to exception if error
Set obj2 = ##class(MyApp.Person).%OpenId(42, , .sc)
$$$ThrowOnError(sc)
// Now both system errors AND status errors are
// caught by the same CATCH block
Set result = obj2.Name _ " processed"
Return $$$OK
}
CATCH ex {
// Single error handling point
// Convert exception back to %Status for the caller
Return ex.AsStatus()
}
}
Conversión de Excepción a %Status
Include %occStatus
ClassMethod ExceptionToStatus() As %Status
{
TRY {
// Some operation that may throw
Do ..RiskyOperation()
Return $$$OK
}
CATCH ex {
// ex.AsStatus() converts any exception to %Status
Return ex.AsStatus()
}
}
Creación de Excepción a Partir de %Status (Explícitamente)
Include %occStatus
ClassMethod CreateStatusException()
{
Set sc = $$$ERROR($$$GeneralError, "Something failed")
// Create an exception from a status (without throwing)
Set ex = ##class(%Exception.StatusException).CreateFromStatus(sc)
// Now you have an exception object you can inspect
Write "Name: ", ex.Name, !
Write "Code: ", ex.Code, !
Write "Display: ", ex.DisplayString(), !
// Or throw it
// THROW ex
}
Comparación Lado a Lado
Include %occStatus
/// Side-by-side: same logic, different patterns
ClassMethod ComparePatterns()
{
// ===== STATUS PATTERN =====
Set sc = ..DoWork1()
If $$$ISERR(sc) {
Set sc2 = ..DoCleanup()
If $$$ISERR(sc2) {
// Compound error - append
Set sc = $SYSTEM.Status.AppendStatus(sc, sc2)
}
Do $SYSTEM.Status.DisplayError(sc)
Quit
}
// ===== EXCEPTION PATTERN =====
TRY {
Do ..DoWork2()
}
CATCH ex {
TRY {
Do ..DoCleanup()
}
CATCH cleanupEx {
// Log cleanup failure too
}
Write ex.DisplayString(), !
}
}
La Plantilla Estándar de Método
Include %occStatus
/// This is the standard recommended pattern for methods
/// that need to return %Status
ClassMethod StandardTemplate(input As %String) As %Status
{
TRY {
// Validate input
If input = "" {
$$$ThrowStatus($$$ERROR($$$GeneralError, "Input required"))
}
// Call methods that return %Status
Set sc = ..Step1(input)
$$$ThrowOnError(sc)
Set sc = ..Step2(input)
$$$ThrowOnError(sc)
// Any system error (<UNDEFINED>, <SUBSCRIPT>, etc.)
// is also caught automatically
Return $$$OK
}
CATCH ex {
Return ex.AsStatus()
}
}
Referencias de Documentación
Resumen de Preparación para el Examen
Conceptos Críticos a Dominar:
- Sintaxis TRY-CATCH: Saber que CATCH recibe un único objeto de excepción de tipo %Exception.AbstractException
- Propiedades de la excepción: Memorizar ex.Name, ex.Code, ex.Data, ex.Location, ex.DisplayString(), ex.AsStatus()
- $$$ThrowOnError vs $$$ThrowStatus: ThrowOnError solo lanza en caso de error; ThrowStatus siempre lanza
- Global ^ERRORS: Saber que almacena errores no manejados automáticamente y es visible en el Management Portal
- $STACK(-1): Devuelve la profundidad de la pila; iterar de 0 a $STACK(-1) con "PLACE" y "MCODE" para la traza completa
- $$$ISERR y $$$ISOK: Nunca comparar %Status directamente con 1 o 0; siempre usar estas macros
- Puente estado-excepción: $$$ThrowOnError convierte estado a excepción; ex.AsStatus() convierte excepción a estado
- Plantilla estándar: Bloque TRY con llamadas $$$ThrowOnError, un solo CATCH que devuelve ex.AsStatus()
Escenarios Comunes de Examen:
- Dado un código con una verificación de error faltante, identificar qué sucede cuando una operación falla
- Elegir entre $$$ThrowOnError y $$$ThrowStatus para una situación específica
- Leer un bloque TRY-CATCH y determinar qué contiene ex.Name o ex.Data para un error dado
- Identificar la forma correcta de convertir entre %Status y excepciones
- Determinar qué devuelve $STACK(n, "PLACE") en varios niveles de la pila
- Reconocer que $SYSTEM.Status.GetErrorText() devuelve una cadena mientras que DisplayError() escribe en el dispositivo
Recomendaciones de Práctica:
- Escribir un método usando la plantilla estándar TRY-CATCH con $$$ThrowOnError
- Causar deliberadamente errores
, y y examinar el objeto de excepción - Crear un método personalizado de registro de errores que capture información de traza con $STACK
- Practicar la conversión entre %Status y excepciones en ambas direcciones
- Crear valores %Status compuestos con AppendStatus y extraer errores individuales
- Navegar al Application Error Log del Management Portal y revisar las entradas
- Usar $SYSTEM.Status.GetErrorText() y DisplayError() con varios estados de error
- Implementar bloques TRY-CATCH anidados y observar qué CATCH maneja cada error