F# 使用委托/DLR Lambdas重写实例方法?
为了学习F和.Net,我一直在玩即将发布的DLR 为此,我一直在研究反射,努力实现一个与clr很好集成的基本类型系统。虽然我能够实例化一个扩展对象的简单类型,但调用它定义的方法时会出错 因为在一天结束时,DLR LambdaExpressions向下编译为委托,我要做的是从生成的委托中取出生成的MethodInfo并调用它,用生成的方法的参数填充堆栈。然后把它还给我。在这一点上,我得到了我的错误 这是我的密码:F# 使用委托/DLR Lambdas重写实例方法?,f#,dynamic-language-runtime,reflection.emit,F#,Dynamic Language Runtime,Reflection.emit,为了学习F和.Net,我一直在玩即将发布的DLR 为此,我一直在研究反射,努力实现一个与clr很好集成的基本类型系统。虽然我能够实例化一个扩展对象的简单类型,但调用它定义的方法时会出错 因为在一天结束时,DLR LambdaExpressions向下编译为委托,我要做的是从生成的委托中取出生成的MethodInfo并调用它,用生成的方法的参数填充堆栈。然后把它还给我。在这一点上,我得到了我的错误 这是我的密码: open System open System.Reflection open Sy
open System
open System.Reflection
open System.Reflection.Emit
type ConstructorInformation=
{Types:System.Type array}
type MethodInformation=
{ParamTypes:System.Type array;
Name:string
Impl:System.Delegate}
let rec addConstructors (t:TypeBuilder) (baseType:System.Type) constructorInfos =
match constructorInfos with
|ci::rest ->
let cb = t.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard,ci.Types)
let ilGen = cb.GetILGenerator()
ilGen.Emit(OpCodes.Ldarg_0)
Array.iteri (fun (index:int) _-> ilGen.Emit(OpCodes.Ldarg, index+1)) ci.Types
ilGen.Emit( OpCodes.Call, baseType.GetConstructor(ci.Types) )
addConstructors t baseType rest
|[] -> ()
let rec addMethods (tb:TypeBuilder) baseType methodInfos =
match methodInfos with
|mi::rest ->
let mb = tb.DefineMethod(mi.Name, MethodAttributes.Public, typeof<obj>, mi.ParamTypes)
let ilGen = mb.GetILGenerator()
ilGen.Emit(OpCodes.Ldarg_0)
Array.iteri (fun index _ -> ilGen.Emit(OpCodes.Ldarg, index+1)) mi.ParamTypes
ilGen.EmitCall(OpCodes.Call, mi.Impl.Method, mi.ParamTypes)
ilGen.Emit(OpCodes.Ret)
addMethods tb baseType rest
|[] -> ()
let defineType (baseType:System.Type) constructorInfos methodInfos=
let ab = AppDomain.CurrentDomain.DefineDynamicAssembly( AssemblyName("test"), AssemblyBuilderAccess.Run)
let mb = ab.DefineDynamicModule("test")
let typeBuilder = mb.DefineType("testType", TypeAttributes.Public, baseType)// | TypeAttributes.Class
addConstructors typeBuilder baseType constructorInfos
addMethods typeBuilder baseType methodInfos
typeBuilder.CreateType()
type Delegate1 = delegate of obj -> obj
let echo y:#obj= (y :> obj)
let del1 : Delegate1 = new Delegate1(echo)
let mis:MethodInformation list=[{Impl=del1; Name="Echo"; ParamTypes=[|(typeof<obj>)|]}]
let cis:ConstructorInformation list=[]
let t= defineType (typeof<obj>) cis mis
let cinfo = t.GetConstructor([||])
let instance =cinfo.Invoke([||])
instance.GetType()
(t.GetMethod("Echo")).Invoke(instance, [| (1:>obj)|])
以下是我的错误,来自fsi:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MethodAccessException: clo@51.Invoke(System.Object)
at testType.Echo(Object )
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at <StartupCode$FSI_0002>.$FSI_0002._main()
stopped due to error
任何帮助或建议都将不胜感激——我是一个.Net新手,所以我的错误可能很简单
迈克·科霍特好吧,我解决了。生成的cil不正确。此外,我还必须对委托进行dynamicinvoke,而不是它所面对的函数
#light
open System
open System.Reflection
open System.Reflection.Emit
type ConstructorInformation=
{Types:System.Type array}
type MethodInformation=
{ParamTypes:System.Type array;
Name:string;
Impl:System.Delegate;
mutable Field:FieldBuilder option}
let rec addConstructors (t:TypeBuilder) (baseType:System.Type) constructorInfos =
match constructorInfos with
|ci::rest ->
let cb = t.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard,ci.Types)
let ilGen = cb.GetILGenerator()
ilGen.Emit(OpCodes.Ldarg_0)
Array.iteri (fun (index:int) _-> ilGen.Emit(OpCodes.Ldarg, index+1)) ci.Types
ilGen.Emit( OpCodes.Call, baseType.GetConstructor(ci.Types) )
addConstructors t baseType rest
|[] -> ()
let rec addMethods (tb:TypeBuilder) baseType methodInfos =
match methodInfos with
|mi::rest ->
let fb = tb.DefineField(mi.Name+"_field", typeof<Delegate>, FieldAttributes.Public);
mi.Field <- Some(fb)
let mb = tb.DefineMethod(mi.Name, MethodAttributes.Public, typeof<obj>, mi.ParamTypes)
let ilGen = mb.GetILGenerator()
let arrayLocal = ilGen.DeclareLocal((typeof<obj[]>))
ilGen.Emit(OpCodes.Ldarg_0)
ilGen.Emit(OpCodes.Ldfld, fb)
ilGen.Emit(OpCodes.Ldc_I4, Array.length mi.ParamTypes)
ilGen.Emit(OpCodes.Newarr, typeof<obj>)
ilGen.Emit(OpCodes.Stloc, arrayLocal)
ilGen.Emit(OpCodes.Ldloc, arrayLocal)
Array.iteri (fun index _ -> ilGen.Emit(OpCodes.Ldc_I4, index)
ilGen.Emit(OpCodes.Ldarg, index+1)
ilGen.Emit(OpCodes.Stelem_Ref)
ilGen.Emit(OpCodes.Ldloc, arrayLocal)) mi.ParamTypes
ilGen.EmitCall(OpCodes.Callvirt, (mi.Impl.GetType()).GetMethod("DynamicInvoke", [|(typeof<obj[]>)|]), mi.ParamTypes)
ilGen.Emit(OpCodes.Ret)
addMethods tb baseType rest
|[] -> ()
let defineType (baseType:System.Type) constructorInfos methodInfos=
let ab = AppDomain.CurrentDomain.DefineDynamicAssembly( AssemblyName("test"), AssemblyBuilderAccess.Run)
let mb = ab.DefineDynamicModule("test")
let typeBuilder = mb.DefineType("testType", TypeAttributes.Public, baseType)// | TypeAttributes.Class
addConstructors typeBuilder baseType constructorInfos
addMethods typeBuilder baseType methodInfos
typeBuilder.CreateType()
type Delegate1 = delegate of obj -> obj
let echo y:#obj= (y :> obj)
let del1 : Delegate1 = new Delegate1(echo)
type Delegate2 = delegate of obj * obj -> obj
let echoFirst (x:#obj) (y:#obj)=(x:>obj)
let echoFirstDelegate:Delegate2 = new Delegate2(echoFirst)
echoFirstDelegate.DynamicInvoke( [|(1:>obj);(2:>obj)|])
//let mis:MethodInformation list=[{Impl=del1; Name="Echo"; ParamTypes=[|(typeof<obj>)|];Field=None}]
//let cis:ConstructorInformation list=[]
//let t= defineType (typeof<obj>) cis mis
//let cinfo = t.GetConstructor([||])
//let instance =cinfo.Invoke([||])
//instance.GetType()
//(t.GetField("Echo_field")).SetValue(instance, del1)
//let fieldDelegate = (t.GetField("Echo_field")).GetValue(instance) :?> Delegate
//(t.GetMethod("Echo")).Invoke(instance, [| (1:>obj)|])
//del1.DynamicInvoke( [|(1:>obj)|])
let mis:MethodInformation list=[{Impl=del1; Name="Echo"; ParamTypes=[|(typeof<obj>)|];Field=None};
{Impl=echoFirstDelegate; Name="EchoFirst"; ParamTypes=[| (typeof<obj>);(typeof<obj>)|]; Field=None}]
let cis:ConstructorInformation list=[]
let t= defineType (typeof<obj>) cis mis
let cinfo = t.GetConstructor([||])
let instance =cinfo.Invoke([||])
instance.GetType()
(t.GetField("Echo_field")).SetValue(instance, del1)
let fieldDelegate = (t.GetField("Echo_field")).GetValue(instance) :?> Delegate
(t.GetMethod("Echo")).Invoke(instance, [| (1:>obj)|])
(t.GetField("EchoFirst_field")).SetValue(instance, echoFirstDelegate)
(t.GetMethod("EchoFirst")).Invoke(instance, [| (1:>obj);(2:>obj)|])
暗中拍摄-在使用fsc.exe编译时,您是否会获得相同的行为?MethodAccessException表明可能有些东西不是公共的,但您的所有代码似乎都生成了公共方法,所以我不确定为什么会发生这种情况……感谢您的建议,Brian,但看起来它仍然在发生。使用fsc/vs2008编译后,我将通过vs2008的调试异常详细信息窗格获取此消息:System.Reflection.TargetInvocationException未经处理消息:异常已由调用的目标引发。我相信问题在于委托对象本身不在堆栈上……需要一些时间来验证,但我认为这可能是我的问题。根据委托的Method属性,它指向的方法是实例方法。这意味着委托对象本身必须在堆栈上。。。。我从委托的MethodInfo中思考:IsSpecialName=false;IsStatic=假;IsVirtual=false;我现在和这个问题开始时一样不知所措。我尝试了我在上一个问题中提到的方法。我尝试使用newarr操作码将所有arg绑定到一个数组中,然后调用该方法。