利用反射的 API
在某些情况下,在代码中使用反射并不明显,因此 .NET Native 工具链不会保留运行时所需的元数据。 该主题介绍了一些常见的 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);
为使此代码在运行时间能正确运行,需要元数据的几个项。 首先是未得到实例化的泛型类型 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" />
如果实例化是使用 Type.MakeGenericType 方法创建的并且没有遭到静态使用,则 AppClass<T>
上的每个不同的实例化都需要一个不同的指令。
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 Native 工具链不会删除反射调用委托。 如果该方法的动态元数据丢失,当 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" />