Condividi tramite


Macro in X++

Nota

I gruppi di interesse della community sono ora passati da Yammer a Microsoft Viva Engage. Per entrare a far parte di una community Viva Engage e partecipare alle discussioni più recenti, compila il modulo Richiedi l'accesso alla community Viva Engage per Finance and Operations e scegli la community a cui vuoi unirti.

Questo articolo descrive come creare e usare macro in X++.

Le direttive precompilatore, cioè le macro, vengono elaborate concettualmente prima che il codice venga compilato. Le direttive dichiarano e gestiscono le macro e i relativi valori. Le direttive vengono sostituite con il contenuto che designano, così il compilatore non le incontra mai. Il compilatore X++ vede solo la sequenza di caratteri scritti nel codice X++ dalle direttive.

Avviso

Le macro sono funzionalità legacy e potrebbero essere deprecate in future versioni. Usa invece costrutti linguistici: Invece di macro, usa costrutti linguistici come questi:

Definizione dei macro

Definisci una macro nominata usando la sintassi mostrata qui sotto

  • #define. MyMacro(Value) crea una macro con un valore opzionale.
  • #if. MyMacro controlla se una macro è definita.
  • #undef. MyMacro elimina una definizione macro.

#define e #if direttive

Tutte le direttive e i simboli del precompilatore iniziano con il # carattere.

Definisci una macro con la seguente sintassi:

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

Puoi definire una macro ovunque nel tuo codice. La macro può avere un valore che è una sequenza di caratteri, ma non deve necessariamente avere un valore. La #define direttiva istruisce il precompilatore a creare la variabile macro, includendo opzionalmente un valore.

La #if direttiva verifica se la variabile è definita e, opzionalmente, se ha un valore specifico, come mostrato nel seguente esempio:

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

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

Le direttive del precompilatore X++, i nomi delle macro che definiscono e i #if test sui valori delle direttive sono tutti indistinti a maiuscole e minuscole. Tuttavia, definisci i nomi macro che iniziano con una lettera maiuscola.

#undef direttiva

Usa la #undef direttiva per rimuovere una definizione macro che esiste da un precedente #define.

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

Puoi ridefinire il nome di una macro che hai rimosso usando #undef un altro #define.

Utilizzo di un valore macro

È possibile definire un nome di macro in modo che abbia un valore.

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

Un valore macro non ha un tipo di dato particolare: è solo una sequenza di caratteri. Assegnare un valore a una macro fornendo il valore tra parentesi alla fine di una #define.MyMacro direttiva. Usa il simbolo macro ovunque tu voglia che il valore compaia nel codice X++. Un simbolo di macro è il nome della macro con il # carattere aggiunto come prefisso. Nell'esempio di codice seguente viene illustrato un simbolo di macro #MyMacro. Il simbolo viene sostituito dal valore della macro.

Verifica un valore macro

Puoi testare una macro per determinare se ha un valore. Puoi anche determinare se il suo valore è uguale a una specifica sequenza di caratteri. Questi test consentono di includere in modo condizionale righe di codice nel programma X++. Non c'è modo di testare se una macro definita abbia un valore. Puoi solo testare se il valore macro corrisponde a un valore specifico. Come buona pratica, definisci sempre un valore per qualsiasi nome macro tu definisca, oppure non definire mai un valore. Quando si alterna tra queste modalità, il codice diventa difficile da comprendere.

#defInc e #defDec direttive

#defInc e #defDec sono le uniche direttive che interpretano il valore di un macro. Si applicano solo alle macro che hanno un valore che il precompilatore può convertire nel tipo int formale. Queste direttive modificano il valore numerico di una macro al momento della compilazione. Il valore può contenere solo numeri. L'unico carattere non numerico consentito è un segno negativo iniziale (-). Il valore intero viene considerato come un int X++, non come un int64. Per i nomi delle macro che la #defInc direttiva usa, la #define direttiva che crea la macro non dovrebbe risiedere in una dichiarazione di classe. Il comportamento di #defInc in questi casi è imprevedibile. Invece, definisci tali macro solo in un metodo. Usa le #defInc direttive e #defDec solo per macro che hanno un valore intero. Il precompilatore segue regole speciali per #defInc quando il valore della macro non è un intero, o quando il valore è insolito o estremo. Nella tabella seguente sono elencati i valori che #defInc vengono convertiti in zero (0) e quindi incrementati. Quando #defInc converte un valore in 0, non puoi recuperare il valore originale, nemmeno usando #defDec.

Valore macro defInc Value Comportamento
(+55) 56 Il prefisso segno positivo (+) fa sì che il precompilatore tratti questo valore come una stringa non numerica. Il precompilatore considera tutte le stringhe non numeriche come 0 quando gestisce una #defInc direttiva (o #defDec).
("3") 1 I numeri interi racchiusi tra virgolette vengono considerati come 0.
( ) 1 Una stringa di spazi è trattata come 0.
() 1 Una stringa di lunghezza zero è trattata come 0.
(Stringa casuale.) 1 Qualsiasi stringa di caratteri non numerica è trattata come 0.
(0x12) 1 I numeri esadecimali vengono considerati come stringhe non numeriche. Pertanto, il precompilatore li converte in 0.
(-44) -43 I numeri negativi sono accettabili.
(2147483647) -2147483648 Il valore massimo positivo di int trascorre al valore di int minimo negativo di #defInc.
(999888777666555) 1 Qualsiasi numero elevato, oltre la capacità di int e int64.
(5.8) 1 I numeri reali sono interpretati come 0.
1 Quando non vengono forniti valori né parentesi per la direttiva #define.MyValuelessMacro , il valore è 0.

Direttiva #globaldefine

La #globaldefine direttiva è simile alla #define direttiva. Usa #define invece di #globaldefine.

#localmacro e #macro direttive

La #localmacro direttiva è una buona scelta quando vuoi che una macro abbia un valore lungo diverse righe, o quando il valore della tua macro contiene una parentesi di chiusura, rendendola valida per contenere frammenti di codice sorgente.

    #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 direttiva può essere scritta come #macro. Tuttavia, #localmacro è il termine consigliato. Utilizzando la #if direttiva, è possibile verificare se un nome di macro è dichiarato con la #define direttiva. Tuttavia, non puoi testare se il nome della macro viene dichiarato con la #localmacro direttiva. Solo le macro dichiarate utilizzando la #define direttiva sono interessate dalla #undef direttiva. In una #define direttiva è possibile specificare un nome già incluso nell'ambito come #localmacro. L'effetto è quello di scartare e #localmacro creare una #define macro. Questo vale anche per la sequenza opposta, il che significa che a #localmacro può ridefinire un #define. A #localmacro (che ha sia un nome di macro che un valore) sostituisce sempre un precedente #localmacro che ha lo stesso nome. Lo stesso problema si verifica con #globaldefine. La differenza principale tra una #define macro e una #localmacro macro risiede nel modo in cui viene terminata la sintassi. I terminatori sono i seguenti:

  • #define – è terminato da– )
  • #localmacro – è terminato da– #endmacro

#localmacro è una scelta migliore per le macro con più valori di riga. I valori di più righe sono in genere righe di codice X++ o SQL. X++ e SQL contengono molte parentesi e queste terminerebbero prematuramente un #define. Entrambi #define e #localmacro possono essere dichiarati e terminati su una singola riga o su righe successive. In pratica, il #define viene terminato sulla stessa linea su cui è dichiarato. In pratica, il #localmacro viene terminato su una riga successiva.

Parametri macro

È possibile definire i valori delle macro per includere i simboli dei parametri. Il primo simbolo di parametro è %1, il secondo è %2, e così via. I valori per i parametri vengono passati quando si fa riferimento al nome del simbolo della macro per l'espansione. I valori dei parametri macro sono sequenze di caratteri senza tipo formale, e sono delimitati da virgole. Non c'è modo di inserire una virgola come parte di un valore di parametro. Il numero di parametri passati può essere inferiore, maggiore o uguale al numero di parametri che il valore della macro è progettato per ricevere. Il sistema tollera discrepanze nel numero di parametri passati. Se vengono passati meno parametri di quelli previsti dalla macro, ogni parametro omesso viene considerato come una sequenza di caratteri di lunghezza zero.

Nidificazione dei simboli macro

È possibile nidificare le direttive di definizione del precompilatore all'interno di una direttiva di definizione esterna. Le principali direttive di definizione sono #define e #localmacro.

Una #define direttiva può essere data all'interno di una #localmacro direttiva e a #localmacro può essere all'interno di un #define.

#macrolib direttiva

Nell'Application Explor, sotto il nodo Macros sotto il nodo Codice, ci sono molti nodi della libreria che contengono insiemi di direttive macro. Entrambi #define e #localmacro spesso appaiono nel contenuto di queste librerie di macro. È possibile utilizzare il #macrolib. MyAOTMacroLibrary per includere il contenuto di una libreria di macro nel codice X++. Le #if direttive e #undef non si applicano ai #macrolib nomi. Tuttavia, si applicano alle #define direttive che sono il contenuto di una #macrolib macro. La direttiva #macrolib. MyAOTMacroLibrary può anche essere scritto come #MyAOTMacroLibrary. Il #macrolib prefisso è consigliato perché non è mai ambiguo per chi legge il codice in seguito.

Direttiva #linenumber

È possibile utilizzare la direttiva durante lo sviluppo e il #linenumber debug del codice. Viene sostituito dal numero fisico della riga nel file di codice prima di qualsiasi espansione di macro.

Ambito macro

L'intervallo in cui puoi fare riferimento a una macro dipende da dove la definisci. In una classe, puoi fare riferimento alle macro che definisci nella classe genitore. Quando il precompilatore gestisce una classe figlia, prima traccia la catena di eredità fino alla classe root. Il precompilatore poi elabora tutte le direttive dalla classe radice alla classe da compilare. Memorizza tutte le macro e i relativi valori nelle sue tabelle interne. I risultati delle direttive in ogni dichiarazione di classe si applicano alle tabelle interne già popolate da direttive che è stata trovata in precedenza nella catena di ereditariità.

Tuttavia, il precompilatore gestisce ogni metodo separatamente. Aggiorna le sue tabelle interne per poter ripristinare lo stato delle tabelle come erano prima di elaborare il metodo corrente. Dopo che il precompilatore gestisce il primo metodo, ripristina le tabelle interne prima di gestire il metodo successivo.

In questo contesto, un metodo è definito come il contenuto di un nodo del metodo nell'Application Object Tree (AOT). In AOT, puoi espandere il nodo Classi, espandere un nodo di classe, cliccare con il tasto destro su un nodo di metodo e poi selezionare Modifica. È quindi possibile aggiungere una riga prima #define.MyMacro("abc") della dichiarazione del metodo. Il precompilatore considera questa #define direttiva come parte del metodo, anche se si #define verifica all'esterno del {} blocco del metodo.