Compartir vía


Macros en X++

Nota

Los grupos de interés de la comunidad ahora se han trasladado de Yammer a Microsoft Viva Engage. Para unirse a una comunidad de Viva Engage y participar en las últimas discusiones, rellene el formulario Solicitar acceso a la comunidad de Viva Engage de Finance and Operations y elija la comunidad a la que desea unirse.

En este artículo se describe cómo crear y usar macros en X++.

Las directivas del precompilador, es decir, las macros, se procesan conceptualmente antes de compilar el código. Las directivas declaran y controlan macros y sus valores. Las directivas se reemplazan por el contenido que designan, de modo que el compilador nunca las encuentre. El compilador de X++ solo ve la secuencia de caracteres escritos en el código X++ por las directivas.

Advertencia

Las macros son funciones heredadas y podrían quedar obsoletas en futuras versiones. Utiliza constructos de lenguaje en su lugar: En lugar de macros, utiliza constructos de lenguaje como estos:

Definición de macros

Defines una macro con nombre usando la sintaxis que se muestra a continuación

  • #define. MyMacro(Value) crea una macro con un valor opcional.
  • #if. MyMacro comprueba si una macro está definida.
  • #undef. MyMacro elimina una definición de macro.

#define y #if directivas

Todas las directivas y símbolos del precompilador comienzan con el # carácter.

Definamos una macro con la siguiente sintaxis:

#define.MyMacro(Value) // creates a macro with a value.
#define.AnotherMacro() // creates a macro without a value.

Puedes definir una macro en cualquier parte de tu código. La macro puede tener un valor que sea una secuencia de caracteres, pero no necesita tener un valor. La #define directiva indica al precompilador que cree la variable macro, incluyendo opcionalmente un valor.

La #if directiva comprueba si la variable está definida y, opcionalmente, si tiene un valor específico, como se muestra en el siguiente ejemplo:

#if.MyMacro
  // The MyNaacro is defined.
#endif

#ifnot.MyMacro
  // The MyNaacro is not defined.
#endif

Las directivas del precompilador de X++, los nombres de macros que definen y las #if pruebas de valores de directivas son insensibles a mayúsculas y minúsculas. Sin embargo, define los nombres de macros que empiezan con mayúsculas.

#undef directiva

Utiliza la #undef directiva para eliminar una definición de macro que existe de un archivo anterior #define.

#undef.MyMacro
#if.MyMacro
   // The macro is not defined, so this is not included
#endif

Puedes redefinir el nombre de una macro que eliminaste usando #undef otro #define.

Usar un valor de macro

Puede definir un nombre de macro para que tenga un valor.

#define.Offset(42)
...
print #Offset; // 42

Un valor de macro no tiene un tipo de dato concreto, es simplemente una secuencia de caracteres. Asigna un valor a una macro proporcionando el valor incluido entre paréntesis al final de una #define.MyMacro directiva. Usa el símbolo de macro donde quieras que aparezca el valor en el código de X++. Un símbolo de macro es el nombre de la macro con el # carácter agregado como prefijo. En el ejemplo de código siguiente se muestra un símbolo de macro #MyMacro. El símbolo se reemplaza por el valor de la macro.

Prueba de un valor de macro

Puedes probar una macro para determinar si tiene un valor. También puedes determinar si su valor es igual a una secuencia específica de caracteres. Estas pruebas le permiten incluir condicionalmente líneas de código en su programa X++. No hay forma de comprobar si una macro definida tiene un valor. Solo puedes comprobar si el valor de la macro coincide con un valor específico. Como buena práctica, define siempre un valor para cualquier nombre de macro que definas, o nunca definas un valor. Cuando alternas entre estos modos, tu código se vuelve difícil de entender.

#defInc y #defDec directivas

#defInc y #defDec son las únicas directivas que interpretan el valor de una macro. Solo se aplican a macros que tienen un valor que el precompilador puede convertir al tipo int formal. Estas directivas cambian el valor numérico de una macro en tiempo de compilación. El valor solo puede contener números. El único carácter no numérico permitido es un signo negativo inicial (-). El valor entero se trata como un int de X++, no como un int64. Para los nombres de macros que usa la #defInc directiva, la #define directiva que crea la macro no debería residir en una declaración de clase. El comportamiento de #defInc en estos casos es impredecible. En su lugar, definan tales macros solo en un método. Usa las #defInc directivas y #defDec solo para macros que tengan valor entero. El precompilador sigue reglas especiales para #defInc cuando el valor de la macro no es un entero, o cuando el valor es inusual o extremo. En la tabla siguiente se enumeran los valores que #defInc se convierten en cero (0) y, a continuación, se incrementan. Cuando #defInc convierte un valor a 0, no puedes recuperar el valor original, ni siquiera usando #defDec.

Valor macro Valor defInc Comportamiento
(+55) 56 El prefijo de signo positivo (+) hace que el precompilador trate este valor como una cadena no numérica. El precompilador trata todas las cadenas no numéricas como 0 cuando controla una #defInc directiva (o #defDec).
("3") 1 Los enteros entre comillas se tratan como 0.
( ) 1 Una cadena de espacios se trata como 0.
() 1 Una cadena de longitud cero se trata como 0.
(Cadena aleatoria). 1 Cualquier cadena de caracteres no numérica se trata como 0.
(0x12) 1 Los números hexadecimales se tratan como cadenas no numéricas. Por lo tanto, el precompilador los convierte a 0.
(-44) -43 Los números negativos son aceptables.
(2147483647) -2147483648 El valor máximo positivo de int se desborda al valor mínimo negativo de int por #defInc.
(999888777666555) 1 Cualquier número grande, más allá de la capacidad de int e int64.
(5.8) 1 Los números reales se interpretan como 0.
1 Cuando no se proporciona valor ni paréntesis para la directiva #define.MyValuelessMacro , el valor es 0.

#globaldefine directiva

La #globaldefine directiva es similar a la #define directiva. Usa #define en lugar de #globaldefine.

#localmacro y #macro directrices

La #localmacro directiva es una buena opción cuando quieres que una macro tenga un valor de varias líneas, o cuando tu valor de macro contiene un paréntesis de cierre, lo que los convierte en buenos candidatos para contener fragmentos de código fuente.

    #macro.RetailMatchedAggregatedSalesLine(
                %1.price            == %2.price
        &&      %1.businessDate     == %2.businessDate
        &&      %1.itemId           == %2.itemId
        &&      ((((%3) && (%1.qty <= 0)) || ((! %3) && (%1.qty > 0))) || (%4))
    )
    #endmacro

La #localmacro directiva se puede escribir como #macro. Sin embargo, #localmacro es el término recomendado. Mediante el uso de la #if directiva, puede probar si un nombre de macro se declara con la #define directiva. Sin embargo, no puedes comprobar si el nombre de la macro se declara con la #localmacro directiva. Solo las macros declaradas mediante la #define directiva se ven afectadas por la #undef directiva. En una #define directiva, puede especificar un nombre que ya esté en el ámbito como .#localmacro El efecto es descartar y #localmacro crear una #define macro. Esto también se aplica a la secuencia opuesta, lo que significa que a #localmacro puede redefinir a .#define A #localmacro (que tiene un nombre de macro y un valor) siempre invalida un anterior #localmacro que tiene el mismo nombre. Este mismo problema ocurre con #globaldefine. La principal diferencia entre una #define macro y una #localmacro macro está en cómo se termina su sintaxis. Los terminadores son los siguientes:

  • #define – se termina por– )
  • #localmacro – se termina por– #endmacro

#localmacro es una mejor opción para macros con varios valores de línea. Los valores de línea múltiples suelen ser líneas de código X++ o SQL. X++ y SQL contienen muchos paréntesis, y estos terminarían prematuramente un #define. Ambos #define y #localmacro se pueden declarar y terminar en una sola línea o en líneas posteriores. En la práctica, se #define termina en la misma línea en la que se declara. En la práctica, el #localmacro se termina en una línea posterior.

Parámetros macro

Puede definir valores de macro para incluir símbolos de parámetro. El primer símbolo de parámetro es %1, el segundo es %2, y así sucesivamente. Los valores de los parámetros se pasan cuando se hace referencia al nombre del símbolo de macro para la expansión. Los valores de los parámetros macro son secuencias de caracteres sin tipo formal y están delimitados por comas. No hay forma de pasar una coma como como parte de un valor de parámetro. El número de parámetros pasados puede ser menor, mayor o igual que el número de parámetros que el valor de macro está diseñado para recibir. El sistema tolera discrepancias en el número de parámetros pasados. Si se pasan menos parámetros de los esperados por la macro, cada parámetro omitido se trata como una secuencia de caracteres de longitud cero.

Anidamiento de símbolos de macro

Puede anidar directivas de definición del precompilador dentro de una directiva de definición externa. Las principales directivas de definición son #define y #localmacro.

Una #define directiva se puede dar dentro de una #localmacro directiva, y a #localmacro puede estar dentro de un #define.

#macrolib directiva

En el Explorador de Aplicaciones, bajo el nodo Macros bajo el nodo de Código, hay muchos nodos de biblioteca que contienen conjuntos de directivas de macro. Ambos #define y #localmacro a menudo aparecen en el contenido de estas bibliotecas de macros. Puedes usar el #macrolib. MyAOTMacroLibrary para incluir el contenido de una biblioteca de macros en su código X++. Las #if directivas y #undef no se aplican a #macrolib los nombres. Sin embargo, se aplican a #define las directivas que son el contenido de una #macrolib macro. La directiva #macrolib. MyAOTMacroLibrary también puede escribirse como #MyAOTMacroLibrary. El #macrolib prefijo se recomienda porque nunca es ambiguo para una persona que luego lee el código.

Directiva #linenumber

Puede usar la directiva durante el #linenumber desarrollo y la depuración del código. Se reemplaza por el número físico de línea en el archivo de código antes de cualquier expansión de macro.

Alcance macro

El rango en el que puedes referenciar una macro depende de dónde la definas. En una clase, puedes referenciar macros que defines en la clase madre. Cuando el precompilador maneja una clase hija, primero traza la cadena de herencia hasta la clase raíz. El precompilador procesa entonces todas las directivas desde la clase raíz hacia la clase que se está compilando. Almacena todas las macros y sus valores en sus tablas internas. Los resultados de las directivas en cada declaración de clase se aplican a las tablas internas que ya están pobladas a partir de directivas que se encontraron anteriormente en la cadena de herencia.

Sin embargo, el precompilador gestiona cada método por separado. Actualiza sus tablas internas para poder restaurar el estado de las tablas tal y como estaban antes de procesar el método actual. Después de que el precompilador gestiona el primer método, restaura las tablas internas antes de manejar el siguiente método.

En este contexto, un método se define como el contenido de un nodo de método en el árbol de objetos de aplicación (AOT). En el AOT, puedes expandir el nodo Clases, expandir un nodo de clase, hacer clic derecho en un nodo de método y luego seleccionar Editar. A continuación, puede agregar una línea para #define.MyMacro("abc") antes de la declaración del método. El precompilador trata esta #define directiva como parte del método, aunque se #define produzca fuera del {} bloque del método.