Partilhar via


Macros em X++

Observação

Os grupos de interesse da comunidade passaram do Yammer para o Microsoft Viva Engage. Para participar de uma comunidade Viva Engage e participar das últimas discussões, preencha o formulário Solicitar acesso ao Finance and Operations Viva Engage Community e escolha a comunidade à qual deseja participar.

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

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

Advertência

As macros são funcionalidades legadas e podem ser obsoletas em versões futuras. Use construtos de linguagem em vez disso: Em vez de macros, use construtos de linguagem como estes:

Definição de Macros

Defines uma macro nomeada usando a sintaxe mostrada abaixo

  • #define. MyMacro(Value) cria uma macro com um valor opcional.
  • #if. O 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 do pré-compilador começam com o # carácter.

Defina uma macro com a seguinte sintaxe:

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

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

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

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

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

As diretivas do pré-compilador X++, os nomes das macros que definem e os #if testes de valor de diretiva são todos indiferentes a maiúsculas minúsculas. No entanto, defina nomes de macros que começam com letra maiúscula.

#undef diretiva

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

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

Pode redefinir um nome de macro que removeu usando #undef 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 dado específico – é apenas uma sequência de caracteres. Atribuir um valor a uma macro fornecendo o valor incluído entre parênteses no final de uma #define.MyMacro diretiva. Usa o símbolo macro onde quiseres que o valor apareça 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

Podes testar uma macro para determinar se tem um valor. Também pode determinar se o 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á forma de testar se uma macro definida tem um valor. Só podes testar se o valor da macro corresponde a um valor específico. Como boa prática, defina sempre um valor para qualquer nome de macro que defina, ou nunca defina um valor. Quando você alterna entre esses modos, seu código se torna difícil de entender.

Diretivas #defInc e #defDec

#defInc e #defDec são as únicas diretivas que interpretam o valor de uma macro. Aplicam-se apenas a macros que tenham um valor que o pré-compilador pode converter para o tipo int formal. Estas 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 X++ int, não como um int64. Para nomes de macros que a #defInc diretiva utiliza, a #define diretiva que cria a macro não deve residir numa declaração de classe. O comportamento destes #defInc casos é imprevisível. Em vez disso, defina-se tais macros apenas num método. Use as #defInc diretivas and #defDec apenas para macros que tenham valor inteiro. O pré-compilador segue regras especiais para #defInc quando o valor da macro não é um inteiro, ou quando o valor é invulgar ou extremo. A tabela a seguir lista os valores que #defInc convertem em zero (0) e, em seguida, incrementa. Quando #defInc converte um valor para 0, não pode recuperar o valor original, nem sequer usando #defDec.

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

#globaldefine diretiva

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

#localmacro e #macro diretivas

A #localmacro diretiva é uma boa escolha quando queres que uma macro tenha um valor de várias linhas, ou quando o valor da tua macro contém um parêntese de encerramento, tornando-os bons candidatos para 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 redigida 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, não podes testar se o nome da macro é declarado com a #localmacro diretiva. Apenas as macros declaradas pela utilização da #define diretiva são afetadas pela #undef diretiva. Em uma #define diretiva, você pode especificar um nome que já esteja no escopo como um #localmacroarquivo . O efeito é descartar o #localmacro e criar uma #define macro. Isso também se aplica à sequência oposta, o que significa que a #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 #globaldefineo . A principal diferença entre uma #define macro e uma #localmacro macro está em como sua sintaxe é encerrada. Os terminadores são os seguintes:

  • #define – seja rescindido por– )
  • #localmacro – seja rescindido por– #endmacro

#localmacro é uma escolha melhor para macros com vários valores de linha. Vários valores de linha são normalmente linhas de código X++ ou SQL. X++ e SQL contêm muitos parênteses, e estes encerrariam prematuramente um #define. Ambos #define e #localmacro podem ser declarados e terminados em uma única linha ou em linhas subsequentes. Na prática, o #define é terminado na mesma linha onde é declarado. Na prática, o #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 é %2, e 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 dos parâmetros macro são sequências de caracteres sem tipo formal, e são delimitados por vírgulas. Não há forma de passar uma vírgula como parte do valor de um parâmetro. O número de parâmetros passados pode ser menor, 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.

Aninhamento de símbolos de macro

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

Uma #define diretiva pode ser dada dentro de uma #localmacro diretiva, e uma pode ser dentro de #localmacro uma #definediretiva .

#macrolib diretiva

No Explorador de Aplicações, sob o nó Macros sob o nó Código, existem muitos nós de biblioteca que contêm conjuntos de diretivas de macro. Ambos #define e #localmacro muitas vezes 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 seu código X++. As #if diretivas e #undef não se aplicam a #macrolib nomes. No entanto, aplicam-se a #define diretivas que são o conteúdo de uma #macrolib macro. A diretiva #macrolib. A MyAOTMacroLibrary também pode ser escrita como #MyAOTMacroLibrary. O #macrolib prefixo é recomendado porque nunca é ambíguo para quem mais tarde lê o código.

Diretiva #linenumber

Você pode usar a diretiva durante o #linenumber desenvolvimento e a depuração do código. É substituído pelo número físico da linha no ficheiro de código antes de qualquer expansão de macros.

Âmbito macro

O intervalo em que podes referenciar uma macro depende de onde defines a macro. Numa classe, podes consultar macros que defines na classe principal. Quando o pré-compilador lida com uma classe filha, primeiro traça a cadeia de herança até à classe raiz. O pré-compilador processa então todas as diretivas da classe raiz para a classe a compilar. Ele armazena todas as macros e seus valores em suas tabelas internas. Os resultados das diretivas em cada declaração de classe aplicam-se às tabelas internas que já estão preenchidas a partir de diretivas encontradas anteriormente na cadeia de herança.

No entanto, o pré-compilador trata cada método separadamente. Atualiza as suas tabelas internas para poder restaurar o estado das tabelas como estavam antes de processar o método atual. Depois de o pré-compilador tratar do primeiro método, restaura as tabelas internas antes de tratar do método seguinte.

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