マッピング仕様
この章では、.NET オブジェクトと、.NET オブジェクトを表す Caché プロキシ・クラスとの間のマッピングについて説明します。
public とマークされたクラス、メソッド、およびフィールドのみインポートできます。
この章では、以下の種類のマッピングについて説明します。
アセンブリ名とクラス名
アセンブリ名とクラス名は、インポート時に保持されます。ただし、Caché プロキシ・クラス名では、元の .NET クラス名に含まれるアンダースコア (_) はそれぞれ u の文字に置き換えられ、ドル記号 ($) はそれぞれ d の文字に置き換えられます。この u と d では、いずれも大文字と小文字が区別されます (小文字)。
プリミティブ
プリミティブ型とプリミティブ・ラッパは、.NET から Caché に次のようにマッピングされます。
プロパティ
.NET クラスをインポートした結果は、ObjectScript 抽象クラスです。対応するゲッター・メソッドおよびセッター・メソッド (存在すれば、これらはそのままインポートされます) が存在しない .NET プロパティごとに、対応する ObjectScript のゲッター・メソッドおよびセッター・メソッドが .NET ゲートウェイ・エンジンで生成されます。セッターは setXXX、ゲッターは getXXX として生成されます。ここで、XXX はプロパティ名です。例えば、Name という .NET 文字列プロパティをインポートすると、ゲッター・メソッド getName() とセッター・メソッド setName(%Library.String) が生成されます。ゲートウェイでは、すべての静的メンバのクラス・メソッド Get および Set も生成されます。
メソッド
.NET ゲートウェイのインポート操作を実行すると、それによって得られる Caché プロキシ・クラスにあるすべてのメソッドには、.NET にある対応するメソッドと同じ名前が与えられます。ただし、"メソッド名" のセクションで説明する制約があります。また、それらのメソッドは、それぞれ .NET と同じ数の引数を持ちます。すべての Caché プロキシ・メソッドのタイプは %Library.ObjectHandle() です。これは、実行時に .NET ゲートウェイで解決されます。
例えば、以下のような .NET メソッド test は、
public boolean checkAddress(Person person, Address address)
以下のようにインポートされます。
Method checkAddress(p0 As %Library.ObjectHandle,
p1 As %Library.ObjectHandle) As %Library.ObjectHandle
オーバーロードされたメソッド
Caché Basic および ObjectScript ではオーバーロードがサポートされていませんが、オーバーロードされている .NET メソッドを Caché プロキシ・クラスにマッピングすることはできます。これは、最大のメソッド・カーディナリティおよび既定の引数の組み合わせを通じてサポートされます。例えば、2 つ、4 つ、および 5 つの引数を取るバージョンにオーバーロードされている .NET メソッドをインポートする場合、Caché 側で対応できるメソッドは 1 つのみなので、そのメソッドは 5 つの引数 (すべて %ObjectHandleOpens in a new tab 型) をとります。これにより、Caché 側で 2 つ、4 つ、または 5 つの引数を使用して、このメソッドを呼び出すことができます。.NET ゲートウェイ・エンジンは、対応する適切なバージョンの .NET メソッドにディスパッチします。
このスキームは適切に機能しますが、同じ数の引数および同様の型を持つオーバーロードされたメソッドの使用は避けてください。例えば、.NET ゲートウェイは、以下のメソッドを問題なく解決します。
test(int i, string s, float f)
test(Person p)
test(Person p, string s, float f)
test(int i)
しかし、以下のようなメソッドは避けてください。
test(int i)
test(float f)
test(boolean b)
test(object o)
.NET ゲートウェイを使用してより適切な結果が得られるようにするため、オーバーロードされた .NET メソッドの使用は、どうしても必要な場合のみとしてください。
メソッド名
Caché では、メソッド名について 31 文字の長さ制限があります。.NET メソッド名の長さが 31 文字を超えないようにしてください。名前の長さが 31 文字を超える場合、Caché プロキシ・メソッド名は .NET メソッド名の先頭 31 文字のみとなります。例えば、以下のような .NET メソッドがあるとします。
thisDotNetMethodHasAVeryLongName(int i) // 32 characters long
thisDotNetMethodHasAVeryLongNameLength(int i) // 38 characters long
Caché は以下の名前のメソッドを 1 つだけインポートします。
thisDotNetMethodHasAVeryLongNam // 31 characters long
.NET リフレクション・エンジンでは、最初に検出された 1 つがインポートされます。どのメソッドがインポートされたか調べるには、Caché プロキシ・クラス・コードを確認します。できれば、インポートの操作の前にログ機能を有効にしておいてください。.NET ゲートウェイのログ・ファイルには、名前が切り詰められたメソッドや何らかの理由でインポートされなかったメソッドのすべてに関する警告が記録されます。
元のメソッド名のアンダースコア (_) はそれぞれ u の文字に置き換えられ、ドル記号 ($) はそれぞれ d の文字に置き換えられます。この u と d では、いずれも大文字と小文字が区別されます (小文字)。Caché 側に既存の別のメソッド名との重複が予期せず生じた場合、これらの規則に従って、そのメソッドはインポートされません。
最後に、Caché クラス・コードでは、大文字と小文字は区別されません。したがって、大文字と小文字の組み合わせが異なる同じ名前の .NET メソッドが 2 つある場合、そのメソッドのいずれか一方のみがインポートされ、該当の警告がログ・ファイルに書き込まれます。
静的メソッド
Caché は、.NET 静的メソッドを Caché プロキシ・クラスのクラス・メソッドとして投影します。ObjectScript からこれらのメソッドを呼び出すには、以下の構文を使用します。
// calls static .NET method staticMethodName(par1,par2,...)
Do ##class(className).staticMethodName(gateway,par1,par2,...)
コンストラクタ
.NET コンストラクタを呼び出すには、%New() を呼び出します。%New() のシグニチャは、対応する .NET コンストラクタのシグニチャとまったく同じですが、第 1 ポジションに引数 (.NET ゲートウェイのインスタンス) が 1 つ追加されています。%New() はまず、プロキシ・インスタンスを指定されたゲートウェイ・インスタンスに関連付けます。次に、対応する .NET コンストラクタを呼び出します。以下はその例です。
// calls Student(int id, String name) .NET constructor
Set Student=##class(gateway.Student).%New(Gateway,29,"John Doe")
定数
.NET ゲートウェイは、.NET の静的最終変数 (定数) を最終パラメータとして投影およびインポートします。その名前はインポート時に保持されますが、アンダースコア (_) はそれぞれ u の文字に置き換えられ、ドル記号 ($) はそれぞれ d の文字に置き換えられます。この u と d では、いずれも大文字と小文字が区別されます (小文字)。
例えば、以下のような静的最終変数は、
public const int DOTNET_CONSTANT = 1;
以下のように ObjectScript にマッピングされます。
Parameter DOTNETuCONSTANT As INTEGER = 1;
ObjectScript から、以下のようにパラメータにアクセスします。
##class(MyDotNetClass).%GetParameter("DOTNETuCONSTANT"))
OUT パラメータと REF パラメータ
.NET ゲートウェイでは、.NET OUT パラメータと REF パラメータをサポートすることで、パラメータを参照で渡すことができるようにしています。OUT および REF パラメータとして使用できるのはオブジェクトのみであり、スカラ値はサポートされていません。この規則が機能するためには、対応するタイプの一時オブジェクトをあらかじめ割り当てておく必要があります。その後、このメソッドを呼び出し、オブジェクトを参照で渡します。以下に例を示します。
public void getAddressAsReference(out Address address)
ObjectScript からこのメソッドを呼び出すには、一時オブジェクトを作成します。その値を設定する必要はありません。その後、このメソッドを呼び出し、以下のように OUT パラメータを参照で渡します。
Set tempAddress=##class(remote.test.Address).%New(gateway)
Do student.getAddressAsReference(.tempAddress)
以下の例では、OUT パラメータとして Address オブジェクトの配列を返します。
void getOldAddresses(out Address[] address)
ObjectScript から前のメソッドを呼び出すには、以下のコードを使用します。
Set oldAddresses=##class(%ListOfObjects).%New(gateway)
Do person.getOldAddresses(.oldAddresses)
.NET の配列
プリミティブ型の配列およびラッパは %Library.ListOfDataTypesOpens in a new tab としてマッピングされます。オブジェクト型の配列は %Library.ListOfObjectsOpens in a new tab としてマッピングされます。1 レベルの添え字のみサポートされます。
ゲートウェイは .NET のバイト配列 (byte[]) を %Library.GlobalBinaryStreamOpens in a new tab として投影します。同様に、.NET の文字配列 (char[]) を %Library.GlobalCharacterStreamOpens in a new tab として投影します。これにより、バイト配列と文字配列をより効率的に扱うことができます。
バイト配列とストリーム配列は、値または参照によって渡すことができます。参照渡しでは、.NET 側でバイトまたは文字ストリームに変更があった場合に、Caché 側にもその変更が反映されます。以下に例を示します。
System.Net.Sockets.Stream.Read(byte[] buffer, int offset, int size)
.NET のコード :
byte[] buffer = new byte[maxLen];
int bytesRead = inputStream.Read(buffer,offset,maxLen);
対応する ObjectScript コード :
Set readStream=##class(%GlobalBinaryStream).%New()
// we need to 'reserve' a number of bytes since we are passing the stream
// by reference (DotNet's equivalent is byte[] ba = new byte[max];)
For i=1:1:50 Do readStream.Write("0")
Set bytesRead=test.read(.readStream,50)
Write readStream.Read(bytesRead)
以下の例では、文字ストリームが値渡しされるので、対応する .NET char[] を変更しても Caché 側には反映されません。
Set charStream=##class(%GlobalCharacterStream).%New()
Do charStream.Write("Global character stream")
Do test.setCharArray(charStream)
再キャスト
ObjectScript の再キャストに対するサポートには、メソッド呼び出しの時点でのみ再キャストが可能であるという制限があります。ただし、すべての Caché プロキシは抽象クラスなので、これで十分です。
.NET 標準出力のリダイレクト
.NET ゲートウェイは、対応する .NET コード内の標準 .NET 出力を呼び出し元の Caché セッションに自動的にリダイレクトします。.NET メソッド呼び出しでの System.out に対する呼び出しをすべて収集し、これらを Caché に送信して、.NET からコードを実行したときの表示と同じ形式で表示します。この動作を無効にして、.NET コードで指定したように標準の出力デバイス (多くの場合はコンソール) に出力するには、セッションが実行している場所のネームスペースで以下のグローバル参照を設定します。
Set ^%SYS("Gateway","Remote","DisableOutputRedirect") = 1
制限条件
.NET ゲートウェイ・エンジンは、生成できないメンバがある場合、インポートを中断するのではなく、生成できないすべてのメンバを通知せずにスキップします。ユーザがログ機能を有効にした状態でインポート手順を繰り返すと、スキップされたすべてのメンバ (およびスキップの理由) がログ・ファイルの WARNING セクションに記録されます。
.NET ゲートウェイ・エンジンは、アセンブリとメソッドの名前、パラメータ型などを必ず保持しようとします。したがって、Caché プロキシ・メソッドを呼び出すことは、対応する .NET のメソッドを呼び出すこととほとんど同じです。そのため、.NET コードを記述するときには、Caché Basic および ObjectScript の制限事項に注意してください。ほとんどの場合、まったく問題ありませんが、以下のような Caché Basic または ObjectScript の制限が適用されることがあります。
-
.NET メソッド名の長さが 30 文字を超えてはいけません。
-
引数が 100 個以上あってはいけません。
-
長さが 32 K を超えている文字列オブジェクトを渡そうとしてはいけません。
-
.NET では大文字と小文字が区別されることを前提にメソッド名を選択してはいけません。
-
インスタンス・メソッドを上書きする静的メソッドをインポートしようとしてはいけません。
-
.NET ゲートウェイは、.NET の汎用クラスのプロキシ・クラスを生成できません。同様に、汎用サブクラスまたはサブインタフェースを持つ .NET クラスをインポートすることもできません。
-
.NET イベントはサポートされません。Caché コードを委任通知から呼び出すことはできません。
Caché Basic および ObjectScript の名前付け規約の詳細は、"Caché ObjectScript の使用法" の "変数"、"Caché オブジェクトの使用法" の "名前付け規約"、"Caché Basic の使用法" の "識別子と変数"、および "Caché プログラミング入門ガイド" の "識別子のルールとガイドライン" を参照してください。