次の方法で共有


X++ でのマクロ

コミュニティの関心グループが Yammer から Microsoft Viva Engage に移行されました。 Viva Engage コミュニティに参加し、最新のディスカッションに参加するには、「 Finance and Operations Viva Engage Community へのアクセスを要求する 」フォームに入力し、参加するコミュニティを選択します。

この記事では、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 は、マクロの値を解釈する唯一のディレクティブです。 プリコンパイラーが正式な int 型に変換できる値を持つマクロにのみ適用されます。 これらのディレクティブは、コンパイル時にマクロの数値を変更します。 値には数値のみを含めることができます。 唯一の数字以外の文字は、先頭にマイナス記号 (-) が付いています。 整数値は、int64 ではなく、X++ int として扱われます。 #defInc ディレクティブが使用するマクロ名の場合、マクロを作成する#define ディレクティブはクラス宣言に存在してはなりません。 これらの場合の #defInc の動作は予測できません。 代わりに、メソッドでのみこのようなマクロを定義します。 #defIncディレクティブと#defDec ディレクティブは、整数値を持つマクロにのみ使用します。 プリコンパイラーは、マクロ値が整数でない場合、または値が異常または極端な場合に、 #defInc に関する特別な規則に従います。 次のテーブルは、#defInc がゼロ (0) に変換してから増分する値を示しています。 #defInc値を 0 に変換する場合、#defDecを使用しても元の値を回復できません。

マクロの値 defInc 値 動作
(+55) 56 正符号 (+) プレフィックスを指定すると、プリコンパイラーはこの値を数値以外の文字列として扱います。 プリコンパイラは、#defInc (または #defDec) ディレクティブを扱うとき、数値以外のすべての文字列を 0 として処理します。
(「3」) 1 引用符で囲まれた整数は、0 として扱われます。
( ) 1 スペースの文字列は 0 として扱われます。
() 1 長さ 0 の文字列は 0 として扱われます。
(ランダムな文字列です。) 1 数値以外の文字の文字列は 0 として扱われます。
(0x12) 1 16 進数は、数値以外の文字列として扱われます。 したがって、プリコンパイラーはそれらを 0 に変換します。
(-44) -43 負の数でもかまいません。
(2147483647) -2147483648 最大正の int 値は、によって最小の負#defInc 値にオーバーフローします。
(999888777666555) 1 int および int64 の容量を超えた大きな数。
(5.8) 1 実数は 0 と解釈されます。
1 ディレクティブに値がなく、かっこが指定されていない場合 #define.MyValuelessMacro 値は 0 になります。

#globaldefine ディレクティブ

#globaldefine ディレクティブは、#define ディレクティブに似ています。 #defineの代わりに #globaldefine を使用します。

ディレクティブの #localmacro と #macro

#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 マクロが作成されます。 これは反対のシーケンスにも当てはまります。つまり、#localmacro#define を再定義できます。 (マクロ名と値の両方を持つ) #localmacro は、同じ名前を持つ前の #localmacro を常に上書きします。 この同じ問題が #globaldefine で発生します。 #define マクロと #localmacro マクロの主な違いは、構文がどのように終了するかです。 次のターミネーターがあります。

  • #define - - によって終了)
  • #localmacro - - によって終了#endmacro

#localmacro は、複数の行の値を持つマクロに適しています。 複数の行の値は、通常 X++ または SQL コードの行です。 X++ および SQL には多くのパラメーターが含まれ、これらは処理の途中で #define を終了する場合があります。 #define#localmacro の両方を宣言し、単一行または後続の行で終了することができます。 実際には、 #define は宣言されている行と同じ行で終了します。 実際、#localmacro は後続の行で終了します。

マクロ パラメーター

パラメータ シンボルを含めるようにマクロの値を定義することができます。 最初のパラメーター記号は %1、2 番目のパラメーター記号は %2 で、以降は同様の形式です。 展開のためにマクロ記号名を参照するときは、パラメーターの値を渡します。 マクロ パラメーター値は、仮型のない文字シーケンスであり、コンマ区切りです。 パラメーター値の一部としてコンマを渡す方法はありません。 渡されるパラメーターの数は、マクロ値が受け取るように設計されているパラメーターの数よりも少なくても、大きくても等しくてもかまいません。 システムは、渡されたパラメーターの数の不一致を許容します。 マクロが期待するよりも少ないパラメーターが指定された場合、省略された各パラメーターは、長さが 0 の文字列として扱われます。

入れ子になっているマクロ記号

プリコンパイラ定義ディレクティブは他の外部定義ディレクティブ内に入れ子にすることができます。 主な定義ディレクティブは、#define#localmacro です。

#define ディレクティブは #localmacro ディレクティブ内に指定することができ、また #localmacro#define 内に指定することもできます。

#macrolib ディレクティブ

アプリケーション エクスプローラーの [マクロ] ノードの [コード] ノードには、マクロ ディレクティブのセットを含むライブラリ ノードが多数あります。 多くの場合、#define および #localmacro の両方がこれらのマクロ ライブラリのコンテンツに表示されます。 #macrolib.MyAOTMacroLibrary を使用すると、マクロ ライブラリのコンテンツをユーザーの X++ コードに含めることができます。 #ifディレクティブと#undef ディレクティブは、#macrolib名には適用されません。 ただし、それは #define マクロのコンテンツである#macrolib ディレクティブに適用されます。 ディレクティブ #macrolib。MyAOTMacroLibrary、#MyAOTMacroLibrary として記述することもできます。 #macrolib プレフィックスは、後でコードを読むユーザーにあいまいになることがないため、推奨されます。

#linenumber ディレクティブ

開発中およびコードのデバッグ中は、#linenumber ディレクティブを使用することができます。 マクロを展開する前に、コード ファイル内の物理行番号に置き換えられます。

マクロ スコープ

マクロを参照できる範囲は、マクロを定義する場所によって異なります。 クラスでは、親クラスで定義したマクロを参照できます。 プリコンパイラーは、子クラスを処理するときに、最初に継承チェーンをルート・クラスにトレースします。 プリコンパイラーは、ルート・クラスからコンパイルされるクラスへのすべてのディレクティブを処理します。 内部テーブルにすべてのマクロとその値を格納します。 各クラス宣言のディレクティブの結果は、継承チェーンの前に見つかったディレクティブから既に設定されている内部テーブルに適用されます。

ただし、プリコンパイラーは各メソッドを個別に処理します。 現在のメソッドを処理する前と同じようにテーブルの状態を復元できるように、内部テーブルを更新します。 プリコンパイラーは、最初のメソッドを処理した後、次のメソッドを処理する前に内部テーブルを復元します。

このコンテキストでは、メソッドがアプリケーション オブジェクト ツリー (AOT) でのメソッド ノードのコンテンツとして定義されます。 AOT では、[クラス] ノードを展開し、クラス ノードを展開し、メソッド ノードを右クリックして、[ 編集] を選択できます。 その後、メソッド宣言の前に #define.MyMacro("abc") の行を追加することができます。 プリコンパイラは、#define ディレクティブがメソッドの #define ブロックの外である場合でも、その {} ディレクティブをメソッドの一部として処理します。