X++ でのマクロ
この記事では、X++ でマクロを作成および使用する方法について説明します。
コードをコンパイルする前に、プリコンパイラ ディレクティブが処理されます。 ディレクティブは、マクロとその値を宣言して処理します。 ディレクティブは、プリコンパイラによって削除され、X++ コンパイラがそれらを検出することはありません。 X++ コンパイラは、ディレクティブによって X++ コードに書き込まれた一連の文字だけを認識します。
#define および #if ディレクティブ
すべてのプリコンパイラの指令および記号は #
文字から始まります。 マクロは、コード内の任意の時点で定義できます。 変数は一連の文字である値を持つことができますが、値を持つ必要はありません。 #define
ディレクティブは、省略可能な値を含む、マクロ変数を作成するようプリコンパイラに指示します。 #if
ディレクティブは、変数が定義されているかどうか、および必要に応じて、特定の値があるかどうかをテストします。 X++ プリコンパイラ ディレクティブ、それが定義するマクロ名、および #if
ディレクティブ値テストではすべて、大文字と小文字が区別されます。 ただし、マクロ名を大文字で始めるのがベスト プラクティスです。
#undef ディレクティブ
#undef
ディレクティブを使用すると、以前の #define
から存在するマクロ定義を削除することができます。 マクロ名が #define
によって作成され、#undef
によって削除された後、別の #define
によってマクロが再度作成されます。 #undef
は、#localmacro
ディレクティブで作成されたマクロには影響しません。
マクロ値の使用
値を持つマクロ名を定義することができます。 マクロの値は、文字の並びです。 マクロの値は、データ型の正式な意味での文字列 (または str) ではありません。 #define
ディレクティブの最後にあるかっこで囲まれた値を加えることにより、値をマクロに割り当てます。 X++ コードで発生する値を必要とする箇所ではマクロ記号を使用することができます。 マクロ記号は、接頭語として追加された #
文字を持つマクロの名前です。 次のコード サンプルは、マクロ記号 #MyMacro. を示しています。シンボルはマクロの値に置き換えられます。
マクロ値のテスト
値があるかどうかを確認するマクロをテストすることができます。 また、値が特定の文字の並びと等しいか確認するためにテストすることができます。 これらのテストでは、条件付きで X++ プログラムにコード行を含めることができます。 定義されたマクロに値があるかどうかをテストする方法はありません。 特定の値がマクロの値に一致するかどうかのみテストすることができます。 ベスト プラクティスとしては、定義するマクロ名は常に値を持つ必要があります。または、決して値を持つことができません。 これらのモードを交互に使用するときは、コードを理解することが困難になります。 値を持つマクロについては、フィットの検索時によって異なります。
#defInc および #defDec ディレクティブ
#defInc
および #defDec
は、マクロの値を解釈する唯一のディレクティブであり、正式な int タイプに変換できる値を持つマクロにのみ適用されます。 値は、数字のみを含むことができます。 唯一の数字以外の文字は、先頭にマイナス記号 (-) が付いています。 整数値は、int64 ではなく、X++ int として扱われます。 #defInc
ディレクティブにより使用されるマクロ名については、マクロを作成する #define
ディレクティブがクラス宣言に配置されないようにすることが重要です。 これらの場合の #defInc
の動作は予測できません。 代わりに、このようなマクロはメソッドだけで定義される必要があります。 整数値を持つマクロには #defInc
および #defDec
ディレクティブのみを使用することをお勧めします。 プリコンパイラは、マクロの値が整数でないとき、あるいは値が異常または極端なとき、#defInc
の特別なルールに従います。 次のテーブルは、#defInc
がゼロ (0) に変換してから増分する値を示しています。 #defInc
によって値が 0 に変換されると、#defDec
によっても元の値を回復できません。
マクロの値 | 動作 |
---|---|
(+55) | プラス記号 (+) 接頭語により、プリコンパイラはこれを数字以外の文字列として扱います。 プリコンパイラは、#defInc (または #defDec ) ディレクティブを扱うとき、数値以外のすべての文字列を 0 として処理します。 |
(「3」) | 引用符で囲まれた整数は、0 として扱われます。 引用符は破棄され、これらの変更はそのまま残ります。 |
( ) | スペースの文字列が 0 として扱われ、増加します。 |
() | 長さゼロの文字列は、0 として処理され、#define.MyMac() のように、値がかっこで囲まれている場合は増加します。 |
(ランダムな文字列です。) | 数値以外の文字列は 0 として扱われ、次に増加します。 |
(0x12) | 16 進数は、数値以外の文字列として扱われます。 したがって、それらは 0 に変換され、次に増分されます。 |
(-44) | マイナス記号 (- ) のない整数を含め、負の数は許容されます。 |
(2147483647) | 最大の正の int 値は、#defInc によって最小の負の int 値に変更されます。 |
(999888777666555) | int および int64 の容量を超えた大きな数。 これは最大の正の int 値として扱われます。 |
(5.8) | 実数は、#defDec (および #defInc ) により切り捨てられます。 後続の記号置き換えは、切り捨てが永続化することを示します。 |
#define.MyValuelessMacro ディレクティブの値とかっこが指定されていない場合は、プリコンパイラは #defInc .MyValuelessMacro ディレクティブの使用を拒否します。 |
#globaldefine ディレクティブ
#globaldefine
ディレクティブは、#define
ディレクティブに似ています。 違いは、#define
ディレクティブは一般的に #globalmacro
ディレクティブよりも優先されるということです。 これは、どのディレクティブが最初に X++ コードで発生するかに関係なく当てはまります。 #globaldefine
は、マクロ名と値の両方を持つ #define
ディレクティブを上書きすることはありません。 #globaldefine
は別の #globaldefine
を上書きする場合があります。 名前のみを含む #define
ディレクティブでは、名前と値の両方を含む #globalmacro
が上書きされません。 #define,
を使用し、#globaldefine.
を使用しないようにお勧めします。#globaldefine
の使用によって不確定性が生じ、コードの保守が困難になる場合があります。 #globaldefine
の正確なセマンティクスは、#if
テスト ディレクティブでは達成できません。 #if
テストを使用すると、#define
と #globaldefine.
の上書きを回避できます。ただし #if
テストは #define
と #globaldefine
マクロを区別することはできません。
マクロ パラメーター
パラメータ シンボルを含めるようにマクロの値を定義することができます。 最初のパラメーター記号は %1
、2 番目のパラメーター記号は %2
で、以降は同様の形式です。 展開のためにマクロ記号名を参照するときは、パラメーターの値を渡します。 マクロ パラメーターの値は、正式な型のない文字シーケンスで、コンマで区切られます。 パラメーター値の一部としてカンマで渡す方法はありません。 渡されるパラメーターの数は、マクロ値が受け取るように設計されているパラメーターの数よりも少なくても、大きくても等しくてもかまいません。 システムは、渡されたパラメーターの数の不一致を許容します。 マクロが期待するよりも少ないパラメーターが指定された場合、省略された各パラメーターは、長さが 0 の文字列として扱われます。
#localmacro および #globalmacro ディレクティブ
#localmacro
ディレクティブは、複数の行にまたがる値をマクロに設定する場合や、マクロの値に閉じかっこが含まれている場合に推奨されます。 #localmacro
ディレクティブは、マクロの値を数行の X++ または SQL コードにする場合に推奨されます。 #localmacro
ディレクティブは、#macro
として記述することができます。 ただし、#localmacro
が勧められている用語です。 どちらのマクロも同じ動作をします。 #if
ディレクティブを使用することにより、マクロ名が #define
ディレクティブで宣言されているかどうかをテストできます。 ただし、マクロ名が #localmacro
ディレクティブで宣言されているどうかをテストすることはできません。 #define
ディレクティブを使用して宣言されたマクロのみ、#undef
ディレクティブの影響を受けます。 #define
ディレクティブでは、既にスコープ内にある名前を #localmacro
として指定できます。 結果として、#localmacro
が破棄され、#define
マクロが作成されます。 これは反対のシーケンスにも当てはまります。つまり、#localmacro
は #define
を再定義できます。 (マクロ名と値の両方を持つ) #localmacro
は、同じ名前を持つ前の #localmacro
を常に上書きします。 ただし、#globalmacro.
を使用する場合上書きが行われるかどうかは必ずしも確認できません。このため、#globalmacro
を使用しないことをお勧めします。 この同じ問題が #globaldefine
で発生します。 #define
マクロと #localmacro
マクロの主な違いは、構文がどのように終了するかです。 次のターミネーターがあります。
#define
は)
によって終了#localmacro
は#endmacro
によって終了
#localmacro
は、複数の行の値を持つマクロに適しています。 複数の行の値は、通常 X++ または SQL コードの行です。 X++ および SQL には多くのパラメーターが含まれ、これらは処理の途中で #define を終了する場合があります。 #define
と #localmacro
の両方を宣言し、単一行または後続の行で終了することができます。 実際、#define
は宣言されている同じ行で終了します。 実際、#localmacro
は後続の行で終了します。 マクロ名と値の両方を指定すると、#globalmacro
ディレクティブは #define ディレクティブを上書きできません。 また、#globaldefine
ディレクティブは #localmacro
ディレクティブへの上書きができません。
入れ子になっているマクロ記号
プリコンパイラ定義ディレクティブは他の外部定義ディレクティブ内に入れ子にすることができます。 主な定義ディレクティブは、#define
と #localmacro
です。
#define
ディレクティブは #localmacro
ディレクティブ内に指定することができ、また #localmacro
を #define
内に指定することもできます。
#macrolib ディレクティブ
マクロ ノードの下のアプリケーション エクスプローラーには、マクロ ディレクティブのセットが含まれる多くのライブラリ ノードがあります。 多くの場合、#define
および #localmacro
の両方がこれらのマクロ ライブラリのコンテンツに表示されます。 #macrolib.MyAOTMacroLibrary を使用すると、マクロ ライブラリのコンテンツをユーザーの X++ コードに含めることができます。 #if
および #undef
ディレクティブは、#macrolib
名には適用されません。 ただし、それは #macrolib
マクロのコンテンツである#define
ディレクティブに適用されます。 ディレクティブ #macrolib.MyAOTMacroLibrary は、#MyAOTMacroLibrary として書き込むこともできます。#macrolib
プレフィックスを使うと後でコードを読むときにあいまいにならないため、推奨されます。
#linenumber ディレクティブ
開発中およびコードのデバッグ中は、#linenumber
ディレクティブを使用することができます。 これは、コード ファイル内の物理的な行番号に置き換えられます。
マクロの範囲 (スコープ)
マクロが参照できる範囲は、マクロが定義されている場所によって異なります。 クラスでは、親クラスで定義されているマクロを参照できますが、子クラスで定義されているマクロを参照することはできません。 プリコンパイラが子クラスを処理するとき、プリコンパイラは最初に最上位の直系のクラスへの継承チェーンを追跡します。 プリコンパイラは、上位クラスのクラス宣言部分からのすべてのディレクティブを処理します。 内部テーブルにすべてのマクロとその値を格納します。 プリコンパイラは、同じ方法で、継承チェーン内の次のクラスを処理します。 各クラス宣言でのディレクティブの結果は、継承チェーンの初期段階で見つかったディレクティブからすでに入力されている内部テーブルに適用されます。 プリコンパイラは、ターゲットの子クラスに達すると、もう一度クラス宣言部分を処理します。 ただし、次に一連の個別操作で各メソッドを処理します。 プリコンパイラは、内部テーブルの状態を現在のメソッドの処理を開始する前の状態に復元できる方法で、その内部テーブルを更新します。 最初のメソッドが処理された後、内部テーブルは次のメソッドが処理される前に復元されます。
メソッドはノードのすべての内容
このコンテキストでは、メソッドがアプリケーション オブジェクト ツリー (AOT) でのメソッド ノードのコンテンツとして定義されます。 AOT で、クラス ノードを展開し、クラス ノードを展開して、メソッドのノードを右クリックしてから編集を選択します。 その後、メソッド宣言の前に #define.MyMacro("abc")
の行を追加することができます。 プリコンパイラは、#define
ディレクティブがメソッドの {}
ブロックの外である場合でも、その #define
ディレクティブをメソッドの一部として処理します。