更新 : 2007 年 11 月
このトピックでは、メタデータ API で使用されるコーディング規則について説明します。
文字列パラメータの処理
メタデータ API は、すべての文字列を Unicode 形式で公開します。実際には、ディスク上のシンボル名形式は UTF-8 ですが、メタデータ API クライアントからは非表示です。返されるすべての文字列は次の 3 つのパラメータから成ります (実際のパラメータ名は異なります)。
[入力] ULONGcchString : 文字列 (終端の null 文字を含む) が返されるバッファのバイト単位によるサイズ。
[出力] LPCWSTRwzString : 文字列が返されるバッファへのポインタ。
[出力] ULONG *pchString : 返される文字列 (終端の null 文字を含む) のサイズへのポインタ。バッファが小さすぎてすべての文字列を格納できない場合、返される文字列は切り捨てられ、エラーが返されます。クライアントは必要に応じてバッファを再割り当てし、再試行できます。
シンボル名
次の規則は、文字列パラメータのシンボル名に適用されます。
シンボル名である文字列パラメータは必ず null で終わることが前提となっており、長さの [入力] パラメータは必要ありません。埋め込み null 文字はサポートされません。
[入力] パラメータ文字列が長すぎて切り捨てなしでは保持できない場合、エラーが返されます。
ユーザー文字列
次の規則は、ユーザー指定文字列パラメータに適用されます。
ユーザー文字列には、null 文字を埋め込むことができ、null 終端文字を含めることはできません。
長さは、cchString パラメータに指定する必要があります。バッファのサイズは、格納される文字列の正確な長さにする必要があります。
既定値の格納
フィールド、パラメータ、およびプロパティの既定値として、定数をメタデータに格納できます。次の 3 つのパラメータを使用して定数を指定します (実際のパラメータ名は異なることがあります)。
[入力] DWORDdwCPlusTypeFlag - 既定値の型を指定する CorElementType 列挙型の値。
[入力] void const *pValue : 実際の既定値へのポインタ。たとえば、0x0000002A を保持する 4 バイトの DWORD へのポインタは、メタデータ内に 42 桁の DWORD 値を格納します。dwCPlusTypeFlag に指定される既定値の型は、プリミティブまたは文字列に限定されます。dwCPlusTypeFlag が ELEMENT_TYPE_CLASS である場合、既定値は null になります。
[入力] ULONGcchValue : pValue がポイントする Unicode 文字数 (バイト シーケンス単位)。これは、dwCPlusTypeFlag に指定されている型が ELEMENT_TYPE_STRING である場合のみ必須です。他の場合はすべて、長さは型から推論されます。
既定値は、初期化コードと静的に初期化されたデータ領域のいずれにも自動挿入されません。これらは、単純にメタデータ内に記録されます。
既定値を指定しない場合、dwCPlusTypeFlag のすべてのビットを設定します (値を -1 に設定します)。
戻り値を受け取るパラメータの null ポインタ
メタデータ API は最低限のエラー チェックを行うため、次の状況では戻り値を受け取るパラメータに非 null ポインタを想定しています。
Define メソッドでは、返されたトークンに対して非 null ポインタが必要です。これらのメソッドは、定義するアイテムを作成し、アイテムのトークンを返します。必要ない場合はトークンを破棄することを選択できます。
Find メソッドは、アイテムのトークンが正常に見つかった場合は常にそのトークンを返します。
Get メソッドでは、戻す必要がないパラメータ内に null を渡すことができます。
Set メソッドには、通常は戻り値がありません。トークン内に、更新する値と一緒に更新するアイテムを渡すと、メソッドが更新を実行します。
無視されるパラメータ値
メタデータ API のいくつかのメソッドでは、以前に定義したアイテムのプロパティを変更できます。次の例では、IMetaDataEmit::SetFieldProps メソッドを使用してフィールドのプロパティを変更します。プロパティは事前に IMetaDataEmit::DefineField への呼び出しで指定されていました。
HRESULT SetFieldProps(mdFieldDef fd, DWORD dwFieldFlags,
DWORD dwDefType, void const *pValue, ULONG cchValue)
dwFieldFlags と pValue の一方のみを変更し、一方を変更しない場合があります。この場合、パラメータ値を変更しない場合でも、エラーを避けるためにパラメータ値を渡す必要があります。ただし、その値を変更しない場合、特定の値を渡すことにより、その引数を無視するように指定できます。メソッドの引数を無視する場合にメタデータ API は次の規則を使用します。
パラメータがポインタ型である場合、null ポインタを渡します。
パラメータが値型である場合 (通常はフラグ ビットマスク)、すべてのビットを設定する値 (–1) を渡します。
返されるエラー
IMetaDataDispenserEx、IMetaDataEmit、および IMetaDataImport の各インターフェイスでは、ほとんどすべてのメソッドが結果を示す HRESULT 値を返します。操作が成功した場合は、これは値 S_OK です。呼び出しがエラーになった場合は、操作が失敗した理由を説明する別の値が返されます。
すべてのメタデータ API で一般的なパターンとしては、呼び出し元が結果よりも小さい文字列バッファを指定すると、API はできるだけ多くの数の文字をコピーし、S_OK ではなく、CLDB_S_TRUNCATION の HRESULT 値を返します。
IMetadata インターフェイスの呼び出し元はコンパイラまたはツールです。エラーを検出するために、呼び出し元が各呼び出しのリターン ステータスを常にチェックすることが重要です。この場合、エラー条件はユーザー (アプリケーション プログラムなど) ではなく、直接の呼び出し元 (コンパイラなど) の問題を反映します。
メモリ管理
汎用 COM の既定では、呼び出し先が割り当てたメモリは呼び出し元が解放します。ただし、メタデータ メソッドの動作は異なります。
多くのメタデータ メソッドは、メモリのブロックに対する [出力] ポインタを返します。このようなメモリは、モジュールのメタデータ ヒープの一部であり、共通言語ランタイム (CLR: Common Language Runtime) によって所有されます。したがって、CLR が所有するメタデータのメモリ内ストレージを直接示すポインタを受け取るので、アプリケーションでメモリを解放する必要はありません。
ジェネリックのサポート
.NET Framework Version 2.0 では、メタデータ API は大幅に拡張され、ジェネリック (別名 "パラメータ ポリモーフィズム") をサポートしています。ジェネリックは C++ のテンプレートに似ています。次の例は、C# でジェネリック クラスを定義しています。
public class Dictionary<Key, Val> { . . . }
この場合、Dictionary クラスは Key と Val という 2 つのジェネリック パラメータを使用してパラメータ化されています。このクラスをインスタンス化する場合、次の例のようにジェネリック パラメータの型を選択します。
Dictionary<string, int> NameToPhone = new Dictionary<string, int>();
Dictionary<int, string> PhoneToName = new Dictionary<int, string>();