利用反射的 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);

为使此代码在运行时间能正确运行,需要元数据的几个项。 首先是未得到实例化的泛型类型 BrowseAppClass<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.CreateInstanceClass1 方法。

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" />

另请参阅