问题描述
我正在尝试使用System.Reflection.Emit中提供的API在F#中进行编译。当我尝试为当前正在构建的程序集中的类型创建函数(代理)时遇到问题。转换以下Java(Java的略微修改版本)类的示例:
class A extends Object {
Integer x;
A (Integer x) {
super();
this.x = x;
}
Function<A,Integer> fun() {
return (A a) -> { return a.x; };
}
}
因此,我需要能够使用Func 的System.Type来生成以下CIL指令:
newobj instance void class [mscorlib]System.Func`2<class tst.A,int32>::.ctor(object,native int)
生成相应指令的代码为:
let deleg = System.Linq.Expressions.Expression.GetDelegateType(types)
let constr = deleg.GetConstructor([|typeof<obj> ; typeof<nativeint>|])
ilGenerator.Emit(OpCodes.Newobj,constr)
其中types
是System.Type元素的数组。对于Fun ,类型数组为[|typ ; typeof<int>|]
,其中typ声明为:let typ : System.Type = upcast typeBuilder
。但是,这会触发以下错误:
System.NotSupportedException: Specified method is not supported.
at System.Reflection.Emit.TypeBuilderInstantiation.GetConstructorImpl(BindingFlags bindingAttr,Binder binder,CallingConventions callConvention,Type[] types,ParameterModifier[] modifiers)
at System.Type.GetConstructor(BindingFlags bindingAttr,ParameterModifier[] modifiers)
如果我需要为使用.NET类型的函数生成相同的指令,例如Func types = [| typeof<int> ; typeof<int> |]
)。对于上述解决方案不起作用的任何建议,或如何检索TypeBuilder的System.Type(尚未完成构建)的任何其他建议,都非常受欢迎。
生成类A的typeBuilder的方式是:
let typeBuilder = moduleBuilder.DefineType(typ,TypeAttributes.Public ||| TypeAttributes.Class)
typeBuilder.SetParent(typeof<obj>)
typeBuilder.DefineField("x",typeof<int>,FieldAttributes.Public)
let constrBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public,CallingConventions.Standard,[|typeof<int>|])
let methodBuilder = typeBuilder.DefineMethod("fun",MethodAttributes.Public)
let delegRetType = System.Linq.Expressions.Expression.GetDelegateType([|typeof<obj> ; typeof<int>|]).GetConstructor([|typeof<obj> ; typeof<nativeint>|]).DeclaringType
methodBuilder.SetReturnType(delegRetType)
methodBuilder.SetParameters([||])
//buildConstrBody - nothing special
//buildMethodBody - generating the instructions using the methodBuilder .GetILGenerator() - triggering the error described above
typeBuilder.CreateType()
请注意,delegRetType
实际上是Func
解决方法
如果我需要为使用.NET类型的函数生成相同的指令,例如Func
,则上述代码可以完美运行(在这种情况下,类型数组为 types = [| typeof<int> ; typeof<int> |]
)。
TypeBuilder
继承自Type
,因此,当您要引用要代表该类型的实例时,只需传递该实例即可。换句话说,您想要的数组是types = [| typeBuilder :> System.Type; typeof<int> |]
如果数组是这样构建的,则它实际上可以工作:
types = [| typeBuilder.GetType(); typeof<int> |]