Compartilhar via


Macros no X++

Observação

Grupos de interesse da comunidade mudaram do Yammer para o Microsoft Viva Engage. Para ingressar em uma comunidade do Viva Engage e participar das discussões mais recentes, preencha o formulário Solicitar acesso às Finanças e Operações viva engage community e escolha a comunidade que você deseja ingressar.

Este artigo descreve como criar e usar macros no X++.

As diretivas de pré-preenchimento, ou seja, macros, são processadas conceitualmente antes que o código seja compilado. As diretivas declaram e manipulam macros e seus valores. As diretivas são substituídas pelo conteúdo que designam, de modo que o compilador nunca as encontra. O compilador X++ vê apenas a sequência de caracteres gravados no código X++ pelas diretivas.

Aviso

As macros são recursos herdados e podem ser preteridas em versões futuras. Em vez disso, use constructos de linguagem: em vez de macros, use constructos de linguagem como estes:

Definindo macros

Você define uma macro nomeada usando a sintaxe mostrada abaixo

  • #define. MyMacro(Value) cria uma macro com um valor opcional.
  • #if. MyMacro verifica se uma macro está definida.
  • #undef. MyMacro remove uma definição de macro.

diretivas #define e #if

Todas as diretivas e símbolos de pré-preenchimento começam com o # caractere.

Defina uma macro com a seguinte sintaxe:

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

Você pode definir uma macro em qualquer lugar em seu código. A macro pode ter um valor que é uma sequência de caracteres, mas não precisa ter um valor. A #define diretiva instrui o pré-compilador a criar a variável de macro, incluindo opcionalmente um valor.

A #if diretiva verifica se a variável está definida e, opcionalmente, se ela tem um valor específico, conforme mostrado no exemplo a seguir:

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

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

As diretivas de pré-preenchimento X++, os nomes de macro definidos e os #if testes de valor de diretiva não diferenciam maiúsculas de minúsculas. No entanto, defina os nomes de macro que começam com uma letra maiúscula.

diretiva #undef

Use a #undef diretiva para remover uma definição de macro que existe de um anterior #define.

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

Você pode redefinir um nome de macro com o qual você removeu #undef usando outro #define.

Usar um valor de macro

Você pode definir um nome de macro para ter um valor.

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

Um valor de macro não tem um tipo de dados específico– é apenas uma sequência de caracteres. Atribua um valor a uma macro fornecendo o valor entre parênteses no final de uma #define.MyMacro diretiva. Use o símbolo de macro onde quiser que o valor ocorra no código X++. Um símbolo de macro é o nome da macro com o # caractere adicionado como um prefixo. O exemplo de código a seguir mostra um símbolo de macro #MyMacro. O símbolo é substituído pelo valor da macro.

Testar um valor de macro

Você pode testar uma macro para determinar se ela tem um valor. Você também pode determinar se seu valor é igual a uma sequência específica de caracteres. Esses testes permitem que você inclua condicionalmente linhas de código em seu programa X++. Não há como testar se uma macro definida tem um valor. Você só pode testar se o valor da macro corresponde a um valor específico. Como prática recomendada, sempre defina um valor para qualquer nome de macro definido ou nunca defina um valor. Quando você alterna entre esses modos, seu código fica difícil de entender.

diretivas #defInc e #defDec

#defInc e #defDec são as únicas diretivas que interpretam o valor de uma macro. Elas se aplicam somente a macros que têm um valor que o pré-compilador pode converter para o tipo de int formal. Essas diretivas alteram o valor numérico de uma macro em tempo de compilação. O valor só pode conter números. O único caractere não numérico permitido é um sinal negativo à esquerda (-). O valor inteiro é tratado como um int X++, não como um int64. Para nomes de macro usados pela #defInc diretiva, a #define diretiva que cria a macro não deve residir em uma declaração de classe. O comportamento desses #defInc casos é imprevisível. Em vez disso, defina essas macros apenas em um método. Use as #defInc diretivas e #defDec somente para macros que tenham um valor inteiro. O pré-compilador segue regras especiais para #defInc quando o valor da macro não é um inteiro ou quando o valor é incomum ou extremo. A tabela a seguir lista os valores que #defInc são convertidos em zero (0) e incrementos. Quando #defInc converte um valor em 0, você não pode recuperar o valor original, nem mesmo usando #defDec.

Valor da macro Valor defInc Comportamento
(+55) 56 O prefixo de sinal positivo (+) faz com que o pré-compilador trate esse valor como uma cadeia de caracteres não numérica. O pré-compilador trata todas as cadeias de caracteres não numéricas como 0 quando trata uma #defInc diretiva (ou #defDec) .
("3") 1 Inteiros entre aspas são tratados como 0.
( ) 1 Uma cadeia de caracteres de espaços é tratada como 0.
() 1 Uma cadeia de caracteres de comprimento zero é tratada como 0.
(Cadeia de caracteres aleatória.) 1 Qualquer cadeia de caracteres não numérica é tratada como 0.
(0x12) 1 Os números hexadecimal são tratados como cadeias de caracteres não numéricas. Portanto, o pré-compilador converte-os em 0.
(-44) -43 Números negativos são aceitáveis.
(2147483647) -2147483648 O valor int positivo máximo transborda para o valor mínimo negativo de int por #defInc.
(999888777666555) 1 Qualquer número grande, além da capacidade de int e int64.
(5.8) 1 Números reais são interpretados como 0.
1 Quando nenhum valor e nenhum parêntese são fornecidos para a diretiva #define.MyValuelessMacro , o valor é 0.

diretiva #globaldefine

A #globaldefine diretiva é semelhante à #define diretiva. Use #define em vez de #globaldefine.

diretivas #localmacro e #macro

A #localmacro diretiva é uma boa opção quando você deseja que uma macro tenha um valor que tenha várias linhas ou quando o valor da macro contiver um parêntese de fechamento, tornando-os bons candidatos a conter fragmentos de código-fonte.

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

A #localmacro diretiva pode ser escrita como #macro. No entanto, #localmacro é o termo recomendado. Usando a #if diretiva, você pode testar se um nome de macro é declarado com a #define diretiva. No entanto, você não pode testar se o nome da macro é declarado com a #localmacro diretiva. Somente as macros declaradas usando a #define diretiva são afetadas pela #undef diretiva. Em uma #define diretiva, você pode especificar um nome que já está no escopo como um #localmacro. O efeito é descartar e #localmacro criar uma #define macro. Isso também se aplica à sequência oposta, o que significa que um #localmacro pode redefinir um #define. Um #localmacro (que tem um nome de macro e um valor) sempre substitui um anterior #localmacro que tem o mesmo nome. Esse mesmo problema ocorre com #globaldefine. A principal diferença entre uma #define macro e uma #localmacro macro está na forma como a sintaxe é encerrada. Os terminadores são os seguintes:

  • #define – é encerrado por: )
  • #localmacro – é encerrado por: #endmacro

#localmacro é uma opção melhor para macros com vários valores de linha. Vários valores de linha normalmente são linhas de código X++ ou SQL. X++ e SQL contêm muitos parênteses, e isso encerraria prematuramente um #define. Ambos #define e #localmacro podem ser declarados e encerrados em uma única linha ou em linhas subsequentes. Na prática, ele #define é encerrado na mesma linha em que é declarado. Na prática, ele #localmacro é encerrado em uma linha subsequente.

Parâmetros de macro

Você pode definir valores de macro para incluir símbolos de parâmetro. O primeiro símbolo de parâmetro é %1, o segundo é %2e assim por diante. Você passa valores para os parâmetros quando faz referência ao nome do símbolo de macro para expansão. Os valores de parâmetro de macro são sequências de caracteres sem tipo formal e são delimitados por vírgula. Não há como passar uma vírgula como parte de um valor de parâmetro. O número de parâmetros passados pode ser menor que, maior ou igual ao número de parâmetros que o valor da macro foi projetado para receber. O sistema tolera incompatibilidades no número de parâmetros passados. Se menos parâmetros forem passados do que a macro espera, cada parâmetro omitido será tratado como uma sequência de caracteres de comprimento zero.

Aninhando símbolos de macro

Você pode aninhar diretivas de definição de pré-preenchimento dentro de uma diretiva de definição externa. As principais diretivas de definição são #define e #localmacro.

Uma #define diretiva pode ser fornecida dentro de uma #localmacro diretiva e pode #localmacro estar dentro de uma #define.

diretiva #macrolib

No Gerenciador de Aplicativos, no nó Macros, no nó Código, há muitos nós de biblioteca que contêm conjuntos de diretivas de macro. Ambas #define e #localmacro frequentemente aparecem no conteúdo dessas bibliotecas de macros. Você pode usar o #macrolib. MyAOTMacroLibrary para incluir o conteúdo de uma biblioteca de macros no código X++. #if E as #undef diretivas não se aplicam a #macrolib nomes. No entanto, elas se aplicam a #define diretivas que são o conteúdo de uma #macrolib macro. A diretiva #macrolib. MyAOTMacroLibrary também pode ser escrito como #MyAOTMacroLibrary. O #macrolib prefixo é recomendado porque nunca é ambíguo para uma pessoa que mais tarde lê o código.

Diretiva #linenumber

Você pode usar a diretiva durante o #linenumber desenvolvimento e a depuração do código. Ele é substituído pelo número de linha física no arquivo de código antes de qualquer expansão de macro.

Escopo da macro

O intervalo no qual você pode referenciar uma macro depende de onde você define a macro. Em uma classe, você pode referenciar macros que você define na classe pai. Quando o pré-compilador manipula uma classe filho, ele primeiro rastreia a cadeia de herança para a classe raiz. O pré-compilador processa todas as diretivas da classe raiz para a classe que está sendo compilada. Ele armazena todas as macros e seus valores em suas tabelas internas. Os resultados das diretivas em cada declaração de classe se aplicam às tabelas internas que já são preenchidas a partir de diretivas encontradas anteriormente na cadeia de herança.

No entanto, o pré-compilador manipula cada método separadamente. Ele atualiza suas tabelas internas para que possa restaurar o estado das tabelas como estavam antes de processar o método atual. Depois que o pré-compilador manipula o primeiro método, ele restaura as tabelas internas antes de manipular o próximo método.

Nesse contexto, um método é definido como o conteúdo de um nó de método na Árvore de Objetos do Aplicativo (AOT). No AOT, você pode expandir o nó Classes, expandir um nó de classe, clicar com o botão direito do mouse em um nó de método e selecionar Editar. Em seguida, você pode adicionar uma linha para #define.MyMacro("abc") antes da declaração do método. O pré-compilador trata essa #define diretiva como parte do método, mesmo que isso #define ocorra fora do {} bloco do método.