Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uwaga / Notatka
Grupy zainteresowań społeczności zostały teraz przeniesione z usługi Yammer do aplikacji Microsoft Viva Engage. Aby dołączyć do społeczności Viva Engage i wziąć udział w najnowszych dyskusjach, wypełnij formularz Żądanie dostępu do aplikacji Finance and Operations Viva Engage Community i wybierz społeczność, którą chcesz dołączyć.
W tym artykule opisano sposób tworzenia i używania makr w języku X++.
Dyrektywy prekompilatora, czyli makra, są koncepcyjnie przetwarzane przed skompilowanym kodem. Dyrektywy deklarują i obsługują makra i ich wartości. Dyrektywy są zastępowane zawartością, którą wyznaczają, więc kompilator nigdy ich nie napotyka. Kompilator X++ widzi tylko sekwencję znaków zapisanych w kodzie X++, zgodnie z dyrektywami.
Ostrzeżenie
Makra są starszymi funkcjami i mogą być przestarzałe w przyszłych wersjach. Zamiast tego należy używać konstrukcji językowych: Zamiast makr użyj konstrukcji językowych, takich jak:
Definiowanie makr
Definiowanie nazwanego makra przy użyciu składni pokazanej poniżej
- #define. MyMacro(Wartość) tworzy makro z opcjonalną wartością.
- #if. MyMacro sprawdza, czy makro jest zdefiniowane.
- #undef. MyMacro usuwa definicję makra.
dyrektywy #define i #if
Wszystkie dyrektywy prekompilera i symbole zaczynają się od # znaku .
Zdefiniuj makro przy użyciu następującej składni:
#define.MyMacro(Value) // creates a macro with a value.
#define.AnotherMacro() // creates a macro without a value.
Makro można zdefiniować w dowolnym miejscu w kodzie. Makro może mieć wartość, która jest sekwencją znaków, ale nie musi mieć wartości. Dyrektywa #define instruuje prekompilera, aby utworzyć zmienną makra, opcjonalnie uwzględniając wartość.
Dyrektywa #if sprawdza, czy zmienna jest zdefiniowana i, opcjonalnie, czy ma określoną wartość, jak pokazano w poniższym przykładzie:
#if.MyMacro
// The MyNaacro is defined.
#endif
#ifnot.MyMacro
// The MyNaacro is not defined.
#endif
Dyrektywy prekompilera X++, nazwy makr, które definiują, a #if testy wartości dyrektywy są bez uwzględniania wielkości liter. Zdefiniuj jednak nazwy makr rozpoczynające się od wielkiej litery.
dyrektywa #undef
#undef Użyj dyrektywy , aby usunąć definicję makra, która istnieje z poprzedniego #defineelementu .
#undef.MyMacro
#if.MyMacro
// The macro is not defined, so this is not included
#endif
Możesz ponownie zdefiniować nazwę makra, która została usunięta #undef za pomocą innego #defineelementu .
Używanie wartości makra
Możesz zdefiniować nazwę makra, aby mieć wartość.
#define.Offset(42)
...
print #Offset; // 42
Wartość makra nie ma określonego typu danych — jest to tylko sekwencja znaków. Przypisz wartość do makra, podając wartość ujętą w nawiasy na końcu #define.MyMacro dyrektywy. Użyj symbolu makra wszędzie tam, gdzie chcesz, aby wartość wystąpiła w kodzie X++. Symbol makra to nazwa makra z # znakiem dodanym jako prefiks. Poniższy przykładowy kod przedstawia symbol makra #MyMacro. Symbol jest zastępowany wartością makra.
Testowanie wartości makra
Możesz przetestować makro, aby określić, czy ma wartość. Można również określić, czy jego wartość jest równa określonej sekwencji znaków. Te testy umożliwiają warunkowe dołączanie wierszy kodu w programie X++. Nie ma możliwości sprawdzenia, czy zdefiniowane makro ma wartość. Można sprawdzić tylko, czy wartość makra jest zgodna z określoną wartością. Najlepszym rozwiązaniem jest zdefiniowanie wartości dla dowolnej zdefiniowanej nazwy makra lub nigdy nie zdefiniowanie wartości. Podczas przełączania między tymi trybami kod staje się trudny do zrozumienia.
dyrektywy #defInc i #defDec
#defInc i #defDec są jedynymi dyrektywami, które interpretują wartość makra. Mają zastosowanie tylko do makr, które mają wartość, którą prekompiler może przekonwertować na formalny typ int . Dyrektywy te zmieniają wartość liczbową makra w czasie kompilacji. Wartość może zawierać tylko liczby. Jedynym niedozwolonym znakiem nieliczbowym jest wiodący znak ujemny (-). Wartość całkowita jest traktowana jako liczba całkowita X++, a nie jako int64. W przypadku nazw makr używanych przez #defInc dyrektywę dyrektywa tworząca #define makro nie powinna znajdować się w deklaracji klasy. Zachowanie #defInc w tych przypadkach jest nieprzewidywalne. Zamiast tego zdefiniuj takie makra tylko w metodzie .
#defInc Użyj dyrektyw i #defDec tylko dla makr, które mają wartość całkowitą. Prekompilator jest zgodny ze specjalnymi regułami, #defInc jeśli wartość makra nie jest liczbą całkowitą lub gdy wartość jest nietypowa lub skrajna. W poniższej tabeli wymieniono wartości, które #defInc są konwertowane na zero (0), a następnie przyrosty. Podczas #defInc konwertowania wartości na 0 nie można odzyskać oryginalnej wartości, nawet przy użyciu polecenia #defDec.
| Wartość makra | defInc Value | Zachowanie |
|---|---|---|
| (+55) | 56 | Prefiks znaku dodatniego (+) sprawia, że prekompiler traktuje tę wartość jako ciąg nieliczbowy. Prekompiler traktuje wszystkie ciągi nieliczbowe jako 0, gdy obsługuje dyrektywę #defInc (lub #defDec). |
| ("3") | 1 | Liczby całkowite ujęte w cudzysłów są traktowane jako 0. |
| ( ) | 1 | Ciąg spacji jest traktowany jako 0. |
| () | 1 | Ciąg o zerowej długości jest traktowany jako 0. |
| (Ciąg losowy). | 1 | Każdy ciąg nieliczbowy znaków jest traktowany jako 0. |
| (0x12) | 1 | Liczby szesnastkowe są traktowane jako ciągi nieliczbowe. W związku z tym prekompiler konwertuje je na wartość 0. |
| (-44) | -43 | Liczby ujemne są dopuszczalne. |
| (2147483647) | -2147483648 | Maksymalna dodatnia wartość int przepełnia się do minimalnej ujemnej wartości int przez #defIncwartość . |
| (999888777666555) | 1 | Dowolna duża liczba, poza pojemnością int i int64. |
| (5.8) | 1 | Liczby rzeczywiste są interpretowane jako 0. |
| 1 | Jeśli dla dyrektywy #define.MyValuelessMacro nie podano żadnych wartości i nawiasów, wartość wynosi 0. |
dyrektywa #globaldefine
Dyrektywa jest podobna #globaldefine#define do dyrektywy. Użyj #define zamiast #globaldefine.
dyrektywy #localmacro i #macro
Dyrektywa #localmacro jest dobrym wyborem, gdy makro ma mieć wartość o długości kilku wierszy lub gdy wartość makra zawiera nawias zamykający, dzięki czemu są dobrymi kandydatami do przechowywania fragmentów kodu źródłowego.
#macro.RetailMatchedAggregatedSalesLine(
%1.price == %2.price
&& %1.businessDate == %2.businessDate
&& %1.itemId == %2.itemId
&& ((((%3) && (%1.qty <= 0)) || ((! %3) && (%1.qty > 0))) || (%4))
)
#endmacro
Dyrektywę #localmacro można napisać jako #macro. Jest #localmacro to jednak zalecany termin. Korzystając z #if dyrektywy, można sprawdzić, czy nazwa makra jest zadeklarowana za #define pomocą dyrektywy . Nie można jednak sprawdzić, czy nazwa makra jest zadeklarowana za #localmacro pomocą dyrektywy . Dyrektywa ma wpływ tylko #define na makra zadeklarowane przy użyciu #undef dyrektywy .
#define W dyrektywie można określić nazwę, która jest już w zakresie jako #localmacro. Efektem jest odrzucenie i #localmacro utworzenie makra #define . Dotyczy to również odwrotnej sekwencji, co oznacza, że #localmacro może ponownie zdefiniować element #define. Wartość #localmacro (która ma zarówno nazwę makra, jak i wartość) zawsze zastępuje poprzednią #localmacro , która ma taką samą nazwę. Ten sam problem występuje w przypadku #globaldefine. Główna różnica między makrem a makrem #define#localmacro polega na tym, jak kończy się ich składnia. Terminatory są następujące:
-
#define– jest przerywany przez:) -
#localmacro– jest przerywany przez:#endmacro
#localmacro jest lepszym wyborem dla makr z wieloma wartościami wierszy. Wiele wartości wierszy to zazwyczaj wiersze kodu X++ lub SQL. X++ i SQL zawierają wiele nawiasów, a te przedwcześnie zakończą #define. Zarówno #define , jak i #localmacro można zadeklarować i zakończyć w jednym wierszu lub w kolejnych wierszach. W praktyce element #define jest przerywany w tym samym wierszu, na który został zadeklarowany. W praktyce element #localmacro jest przerywany w kolejnym wierszu.
Parametry makra
Możesz zdefiniować wartości makr, aby uwzględnić symbole parametrów. Pierwszy symbol parametru to , drugi to %1%2, itd. Wartości parametrów są przekazywane podczas odwołuje się do nazwy symbolu makra w celu rozszerzenia. Wartości parametrów makra to sekwencje znaków bez typu formalnego i są rozdzielane przecinkami. Nie ma możliwości przekazania przecinka jako części wartości parametru. Liczba przekazanych parametrów może być mniejsza niż, większa lub równa liczbie parametrów, które mają zostać odebrane przez wartość makra. System toleruje niezgodność liczby przekazanych parametrów. Jeśli przekazano mniej parametrów niż oczekiwano makra, każdy pominięty parametr jest traktowany jako sekwencja znaków o zerowej długości.
Symbole makr zagnieżdżania
Dyrektywy definicji prekompilera można zagnieżdżać wewnątrz zewnętrznej dyrektywy definicji. Główne dyrektywy definicji to #define i #localmacro.
Dyrektywę #define#localmacro można podać wewnątrz dyrektywy, a element #localmacro może znajdować się wewnątrz #defineelementu .
dyrektywa #macrolib
W Eksploratorze aplikacji w węźle Makra w węźle Kod istnieje wiele węzłów biblioteki, które zawierają zestawy dyrektyw makr. Zarówno, #define jak i #localmacro często pojawiają się w zawartości tych bibliotek makr. Możesz użyć #macrolib. MyAOTMacroLibrary w celu uwzględnienia zawartości biblioteki makr w kodzie X++. Dyrektywy #if i #undef nie mają zastosowania do #macrolib nazw. Mają one jednak zastosowanie do #define dyrektyw, które są zawartością makra #macrolib . Dyrektywa #macrolib. MyAOTMacroLibrary można również napisać jako #MyAOTMacroLibrary. Prefiks #macrolib jest zalecany, ponieważ nigdy nie jest niejednoznaczny dla osoby, która później odczytuje kod.
dyrektywa #linenumber
Dyrektywę #linenumber można użyć podczas opracowywania i debugowania kodu. Jest on zastępowany przez fizyczny numer wiersza w pliku kodu przed rozszerzeniem makra.
Zakres makr
Zakres, w którym można odwoływać się do makra, zależy od tego, gdzie definiuje się makro. W klasie można odwoływać się do makr zdefiniowanych w klasie nadrzędnej. Gdy prekompiler obsługuje klasę podrzędną, najpierw śledzi łańcuch dziedziczenia do klasy głównej. Następnie prekompiler przetwarza wszystkie dyrektywy z klasy głównej do skompilowanej klasy. Przechowuje wszystkie makra i ich wartości w tabelach wewnętrznych. Wyniki dyrektyw w każdej deklaracji klasy mają zastosowanie do tabel wewnętrznych, które są już wypełnione z dyrektyw, które zostały znalezione wcześniej w łańcuchu dziedziczenia.
Jednak prekompiler obsługuje każdą metodę oddzielnie. Aktualizuje on tabele wewnętrzne, aby można było przywrócić stan tabel, tak jak były przed przetworzeniem bieżącej metody. Gdy prekompiler obsługuje pierwszą metodę, przywraca tabele wewnętrzne przed obsługą następnej metody.
W tym kontekście metoda jest definiowana jako zawartość węzła metody w drzewie obiektów aplikacji (AOT). W AOT możesz rozwinąć węzeł Klasy, rozwinąć węzeł klasy, kliknąć prawym przyciskiem myszy węzeł metody, a następnie wybrać polecenie Edytuj. Następnie można dodać wiersz dla przed #define.MyMacro("abc") deklaracją metody. Prekompiler traktuje tę #define dyrektywę jako część metody, mimo że #define występuje poza {} blokiem metody.