備註
社區興趣小組現在已從 Yammer 轉移到 Microsoft Viva Engage。 若要加入 Viva Engage 社群並參與最新的討論,請填寫 [ 要求存取財務和營運 Viva Engage 社群 表單 」 ,並選擇您要加入的社群。
本文說明如何在 X++ 中建立和使用巨集。
預編譯指令,也就是巨集,在程式碼編譯前會先被概念性地處理。 指示詞會宣告並處理巨集及其值。 指令會被它們指定的內容取代,因此編譯器永遠不會遇到它們。 X++ 編譯器只會看到指示詞寫入 X++ 程式碼的字元序列。
定義巨集
你可以用以下語法定義一個命名的巨集
- #define。MyMacro(Value) 建立一個具有可選值的巨集。
- #if。MyMacro 會檢查巨集是否被定義。
- #undef。MyMacro 移除了巨集定義。
#define 和 #if 指令
所有預編譯器的指令和符號都以 # 字元開頭。
定義一個語法為以下語法的巨集:
#define.MyMacro(Value) // creates a macro with a value.
#define.AnotherMacro() // creates a macro without a value.
你可以在程式碼中任何地方定義巨集。 巨集可以有一個字元序列的值,但不一定非得有值。 指令 #define 指示預編譯器建立巨集變數,並可選擇加入一個值。
指令 #if 檢查變數是否被定義,並可選擇性地檢查其是否有特定值,如下範例所示:
#if.MyMacro
// The MyNaacro is defined.
#endif
#ifnot.MyMacro
// The MyNaacro is not defined.
#endif
X++ 的預編譯指令、它們定義的巨集名稱以及 #if 指令值測試都是不區分大小寫的。 不過,請定義以大寫字母開頭的巨集名稱。
#undef 指令
使用 #undef 指令移除先前 中存在 #define的巨集定義。
#undef.MyMacro
#if.MyMacro
// The macro is not defined, so this is not included
#endif
你可以用另一個 #undef重新定義你移除的#define巨集名稱。
使用巨集值
您可以定義巨集名稱以具有值。
#define.Offset(42)
...
print #Offset; // 42
巨集值沒有特定的資料型態——它只是一串字元。 在指令結尾 #define.MyMacro 用括號內標示該值,為巨集指派值。 在 X++ 程式碼中,使用你希望該值出現的位置使用巨集符號。 巨集符號是巨集的名稱,並新增字 # 元作為前置詞。 下列程式碼範例顯示 巨集符號 #MyMacro。 符號會取代為巨集的值。
測試巨集值
你可以測試一個巨集,判斷它是否有價值。 你也可以判斷它的值是否等於某一串特定的字元序列。 這些測試可讓您在 X++ 程式中有條件地包含程式碼行。 沒有辦法測試一個定義的巨集是否有值。 你只能測試巨集值是否符合特定值。 作為最佳實務,無論你定義哪個巨集名稱,都要定義值,或者永遠不要定義值。 當您在這些模式之間交替時,您的程式碼會變得難以理解。
#defInc 和 #defDec 指令
#defInc 和 #defDec 是唯一能解釋巨集價值的指令。 它們只適用於具有預編譯器可轉換為正式 整數 型態的巨集。 這些指令會在編譯時改變巨集的數值。 該值只能包含數字。 唯一允許的非數字字元是前導負號 (-)。 整數值會被視為 X++ int,而不是 int64。 對於指令所使用的巨集名稱 #defInc , #define 創建巨集的指令不應該存在於類別宣告中。 在這些情況下的 #defInc 行為是不可預測的。 相反地,只在一種方法中定義這些巨集。 只有在巨集有整數值時才使用 #defInc and #defDec 指令。 預編譯器會遵循特殊規則,當 #defInc 巨集值非整數,或值異常或極端時。 下表列出轉換成零 (0) 然後遞增的值 #defInc 。 當 #defInc 將值轉換成 0 時,你無法恢復原始值,即使使用 #defDec。
| 巨集價值 | defInc 價值 | 行為 |
|---|---|---|
| (+55) | 56 | 正號(+)前綴使預編譯器將此值視為非數字字串。 前置編譯器在處理 #defInc (或 #defDec) 指示詞時,會將所有非數值字串視為 0。 |
| ("3") | 1 | 以引號括住的整數會被視為 0。 |
| ( ) | 1 | 一串空格視為 0。 |
| () | 1 | 零長度的字串被視為 0。 |
| (隨機字串。 | 1 | 任何非數字字串都視為 0。 |
| (0x12) | 1 | 十六進位數會被視為非數值字串。 因此,預編譯器會將它們轉換為 0。 |
| (-44) | -43 | 負數是可以接受的。 |
| (2147483647) | -2147483648 | 最大正整數值會溢出至最小負整數值。#defInc |
| (999888777666555) | 1 | 任何大數,超出 int 和 int64 的容量。 |
| (5.8) | 1 | 實數則被解釋為 0。 |
| 1 | 當指令沒有提供值或括號時 #define.MyValuelessMacro ,值為 0。 |
#globaldefine 指令
該 #globaldefine 指令類似於 #define 指令。 使用 #define,而不是 #globaldefine。
#localmacro 與 #巨集 指令
#localmacro當你希望巨集值有好幾行長,或是巨集值包含括號,使其成為包含原始碼片段的好候選時,指令是個不錯的選擇。
#macro.RetailMatchedAggregatedSalesLine(
%1.price == %2.price
&& %1.businessDate == %2.businessDate
&& %1.itemId == %2.itemId
&& ((((%3) && (%1.qty <= 0)) || ((! %3) && (%1.qty > 0))) || (%4))
)
#endmacro
該 #localmacro 指令可以寫成 #macro。 但是, #localmacro 是推薦術語。 藉由使用 #if 指引,您可以測試是否使用指引宣 #define 告巨集名稱。 不過,你無法測試巨集名稱是否與指令一起 #localmacro 宣告。 只有使用指引宣 #define 告的巨集會受到 #undef 指引的影響。 在指引中 #define ,您可以將已在範圍內的名稱指定為 #localmacro。 效果是丟棄 並 #localmacro 創建一個 #define 巨集。 這也適用於相反的序列,這意味著 a #localmacro 可以重新定義 。#define A #localmacro (同時具有巨集名稱和值) 一律會覆寫具有相同名稱的先前版本 #localmacro 。 同樣的問題也發生在 上。#globaldefine 巨集和#define巨集之間的#localmacro主要區別在於它們的語法如何終止。 終止符如下:
-
#define– 終止於 –) -
#localmacro– 終止於 –#endmacro
#localmacro 對於具有多行值的巨集來說是更好的選擇。 多行值通常是 X++ 或 SQL 程式碼的行。 X++ 和 SQL 包含許多括號,這些括號會過早終止 #define。 兩者#define都可以#localmacro在單行或後續行上宣告和終止。 實務上,該 #define 線會終止在它宣告的同一條線上。 實際上,會在 #localmacro 後續行上終止。
巨集參數
您可以定義巨集值以包含參數符號。 第一個參數符號是 %1,第二個是 %2,依此類推。 當您參考巨集符號名稱進行展開時,您可以傳遞參數的值。 巨集參數值是沒有形式型別的字元序列,且有逗號分隔。 參數值中沒有辦法在逗號中加入。 傳遞的參數數目可以小於、大於或等於巨集值設計要接收的參數數目。 系統容許傳遞的參數數目不相符。 如果傳遞的參數少於巨集預期的參數,則每個省略的參數都會被視為零長度的字元序列。
巢狀巨集符號
您可以將前置編譯器定義指引巢狀化在外部定義指引內。 主要定義指令是 #define 和 #localmacro。
#define指令可以在指令內#localmacro給出,而 a #localmacro 可以位於 #define.
#macrolib 指令
在應用程式檔案總管中,位於 Macros 節點、Code 節點下方,有許多函式庫節點包含一組巨集指令。 兩者都 #define 經常 #localmacro 出現在這些巨集庫的內容中。 您可以使用 #macrolib。MyAOTMacroLibrary 以將巨集程式庫的內容包含在 X++ 程式碼中。
#if和#undef指令不適用於#macrolib名字。 不過,它們確實適用於 #define 作為巨集內容 #macrolib 的指令。 指令 #macrolib。MyAOTMacroLibrary 也可以寫成 #MyAOTMacroLibrary。 推薦這個 #macrolib 前綴,是因為對後來閱讀程式碼的人來說,這個前綴永遠不會模糊。
#linenumber 指令
您可以在程式碼開發和偵錯期間使用指示 #linenumber 詞。 在任何巨集擴充之前,它會被程式碼檔中的實體行號取代。
宏觀瞄準鏡
你能參考巨集的範圍取決於你定義巨集的位置。 在類別中,你可以參考你在父類別中定義的巨集。 當預編譯器處理子類別時,會先追蹤繼承鏈到根類別。 預編譯器接著會處理所有從根類別到被編譯類別的所有指令。 它將所有巨集及其值儲存在其內部表中。 每個類別宣告中指令的結果會應用於已從繼承鏈中先前找到的指令填充的內部資料表。
然而,預編譯器會分別處理每種方法。 它會更新內部資料表,以恢復處理當前方法前的資料表狀態。 預編譯器處理完第一個方法後,會先還原內部資料表,再處理下一個方法。
在此內容中,方法定義為應用程式物件樹狀結構 (AOT) 中方法節點的內容。 在 AOT 裡,你可以展開 Classes 節點、展開一個類別節點,右鍵點擊方法節點,然後選擇 編輯。 然後您可以在方法聲明之前添加一行 for #define.MyMacro("abc") 。 前置編譯器會將此 #define 指示詞視為方法的一部分,即使 發生 #define 在方法區塊之外 {} 也一樣。