.NET native运行时并不包含JIT编译器,所以其编译的机器码必须是提前生成的。当然有一系列的方法来测试哪些代码是已经生成的,但是这些规则并不能涵盖所有的元编程场景。所以需要在运行时提供指令来进行搜索元编程。同时.NET Native并不能将.NET Framework下的私有成员编译。
下面将介绍如何使用基于反射的API和运行时指令xml文件的配置:
基于反射的API
在一些情况下你并不能得知代码中使用了反射而且.NET Native工具并不会保留运行时需要的元数据。本主题所涵盖的API并不能视为反射的API,但他们是基于反射来执行的。如果你使用这些API的话,需要添加一些信息来运行指令.rd.xml文件,这样就能正常调用这些API,而且不会导致MissingMetadataException的异常。
例如:Type.MakeGenericType method
通过调用这个方法可以在运行时动态生成泛型AppClass
var t = Type.GetType("App1.AppClass`1", true);
Type[] typeArgs = {typeof(int)};
Type t2 = t.MakeGenericType(typeArgs);
Activator.CreateInstance(t2);
为使该代码能够成功运行,需要一些元数据支持。首先是在.rd.xml中添加对AppClass的泛型支持
添加后在.NET Framework下就可以调用Type.GetType()方法来获得对象类型了。
但在.NET Native下调用就会抛出MissingMetadataException的异常。
This operation cannot be carried out as metadata for the following type was removed for performance reasons:
App1.AppClass`1.
你可以在运行时指令文件(.rd.xml)添加下面运行指令来激活对Int32的支持:
Activate="Required Public" />
不同的实例需要不同的指令,添加后就能正常运行。
类似的方法还有:MethodInfo.MakeGenericMethod method, Array.CreateInstance and Type.MakeTypeArray methods
所以,在依赖反射的方法使用时,需要添加对反射类型的支持的指令才可以使用。
运行时指令文件(.rd.xml)配置
运行时指令文件(.rd.xml)是一个xml配置的文件,指定了配置的程序元素是否可用于反射。下面是该文件的一个样例。
Arguments="ContosoClient.DataModel.ProductItem" Serialize="Public" />
Arguments="ContosoClient.DataModel.ProductGroup" Serialize="Public" />
文件结构:
该文件在 http://schemas.microsoft.com/netfx/2013/01/metadata 命名空间下。
根元素Directives是指令元素,可以包含一个或者多个Library元素和零个或者一个Application元素,结构如下
Directives [1:1]
Application [0:1]
Assembly [0:M]
Namespace [0:M]
. . .
Type [0:M]
. . .
TypeInstantiation (constructed generic type) [0:M]
. . .
Namespace [0:M]
Namespace [0:M]
. . .
Type [0:M]
. . .
TypeInstantiation (constructed generic type) [0:M]
. . .
Type [0:M]
Type [0:M]
. . .
TypeInstantiation (constructed generic type) [0:M]
. . .
GenericParameter [0:M]
Method [0:M]
Parameter [0:M]
TypeParameter [0:M]
GenericParameter [0:M]
MethodInstantiation (constructed generic method) [0:M]
Property [0:M]
Field [0:M]
Event [0:M]
TypeInstantiation (constructed generic type) [0:M]
Type [0:M]