リフレクションに依存する API
コード内でのリフレクションの使用は明確ではない場合があるため、.NET ネイティブ ツール チェーンでは、実行時に必要なメタデータを保存しません。 このトピックでは、リフレクション API の一部であるとは見なされないが、正常に実行するためにリフレクションを必要とする、一般的な API と一般的なプログラミング パターンについて説明します。 これらをソース コードで使用している場合、これらに関する情報をランタイム ディレクティブ (.rd.xml) ファイルに追加して、これらの API を呼び出しても MissingMetadataException 例外やその他の例外が実行時にスローされないようにできます。
Type.MakeGenericType メソッド
ジェネリック型 AppClass<T>
を動的にインスタンス化するには、次のようなコードを使用して Type.MakeGenericType メソッドを呼び出します。
var t = Type.GetType("App1.AppClass`1", true);
Type[] typeArgs = {typeof(int)};
Type t2 = t.MakeGenericType(typeArgs);
Activator.CreateInstance(t2);
このコードが実行時に成功するためには、いくつかのメタデータ項目が必要です。 1 つ目は、インスタンス化されていないジェネリック型 Browse
の AppClass<T>
メタデータです。
<Type Name="App1.AppClass`1" Browse="Required PublicAndInternal" />
これにより、Type.GetType(String, Boolean) メソッド呼び出しが成功し、有効な Type オブジェクトが返されます。
ただし、インスタンス化されていないジェネリック型のメタデータを追加した場合でも、Type.MakeGenericType メソッドを呼び出すと、次のような MissingMetadataException 例外がスローされます。
パフォーマンス上の理由から次の種類のメタデータが削除されたため、この操作を実行できません。
App1.AppClass`1<System.Int32>
=
次のランタイム ディレクティブをランタイム ディレクティブ ファイルに追加すると、Activate
の AppClass<T>
に対する特定のインスタンス化の System.Int32 メタデータを追加できます。
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32"
Activate="Required Public" />
AppClass<T>
に対するそれぞれ異なるインスタンス化は、Type.MakeGenericType メソッドにより作成され、かつ静的に使用されていない場合は、個別のディレクティブを必要とします。
MethodInfo.MakeGenericMethod メソッド
ジェネリック メソッド Class1
を持つクラス GetMethod<T>(T t)
があるとすると、GetMethod
は、次のようなコードを使用してリフレクションにより呼び出すことができます。
Type ct = typeof(Class1);
MethodInfo mi = ct.GetMethod("GetMethod");
Type[] typeArgs = {typeof(int)};
object[] parameters = { 12 };
var method = mi.MakeGenericMethod(typeArgs);
Class1 c = new Class1();
method.Invoke(c, parameters);
このコードを正常に実行するには、次のようないくつかのメタデータ項目が必要です。
呼び出すメソッドを持つ型の
Browse
メタデータ。呼び出すメソッドの
Browse
メタデータ。 パブリック メソッドの場合、それを含む型のパブリックBrowse
メタデータを追加しても、メソッドが含められます。呼び出すメソッドの動的メタデータ。これにより、リフレクション呼び出しデリゲートが .NET ネイティブ ツール チェーンにより削除されなくなります。 メソッドの動的メタデータが欠落している場合、MethodInfo.MakeGenericMethod メソッドを呼び出すと、次の例外がスローされます。
MakeGenericMethod() cannot create this generic method instantiation because the instantiation was not metadata-enabled: 'App1.Class1.GenMethod<Int32>(Int32)'.
次のランタイム ディレクティブは、必要なすべてのメタデータが必ず使用可能であるようにします。
<Type Name="App1.Class1" Browse="Required PublicAndInternal">
<MethodInstantiation Name="GenMethod" Arguments="System.Int32" Dynamic="Required"/>
</Type>
MethodInstantiation
ディレクティブは、動的に呼び出されるメソッドの異なるインスタンス化ごとに必要です。Arguments
要素は、それぞれ異なるインスタンス化引数を反映するために更新されます。
Array.CreateInstance メソッドと Type.MakeTypeArray メソッド
次の例は、Type.MakeArrayType 型で Array.CreateInstance メソッドと Class1
メソッドを呼び出します。
Type t = typeof(Class1);
Type at = t.MakeArrayType(1);
Array arr = Array.CreateInstance(at, 10);
配列メタデータが存在しない場合、次のエラーが発生します。
This operation cannot be carried out as metadata for the following type was removed for performance reasons:
App1.Class1[]
Unfortunately, no further information is available.
配列型の Browse
メタデータは、配列を動的にインスタンス化するために必要です。 次のランタイム ディレクティブにより、Class1[]
を動的にインスタンス化できます。
<Type Name="App1.Class1[]" Browse="Required Public" />