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 ディレクティブをメソッドの一部として処理します。