F#と.Netを学ぶために、リリースされる予定のDLRを試してみました。デリゲート/ DLR Lambdaを使用してインスタンスメソッドをオーバーライドするには?
この目的のために、私はclrとうまく統合された基本的なタイプのシステムを実装しようと努力しています。 Objectを継承するシンプルな型をインスタンス化できますが、定義したメソッドを呼び出すときにエラーが発生します。
DLR LambdaExpressionsがデリゲートにコンパイルするため、生成されたデリゲートからMethodInfoを生成し、それを呼び出して、生成されたメソッドの引数をスタックに取り込みます。その後、それを返します。それは私のエラーを取得するこの時点でです。ここで
は私のコードです:
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: [email protected](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
すべてのヘルプや提案が私のミスので、ネットの初心者くさいのビットを - 私はには理解されるであろうシンプルにすることができます。
マイクコホート
暗闇の中で撮影 - fsc.exeでコンパイルすると同じ動作になるのですか? MethodAccessExceptionは、何かがパブリックではないかもしれないと示唆していますが、すべてのコードがパブリックメソッドを生成すると思われるので、なぜそれが起こっているのかわかりません... – Brian
Brianの提案に感謝します。 FSC/VS2008でこれをコンパイルした後、私はこの(VS2008のデバッグを経由して「例外の詳細」ペイン)を取得しています: System.Reflection.TargetInvocationExceptionは、未処理の メッセージだった:呼び出しのターゲットが例外をスローされました。 –
私は、デリゲートオブジェクト自体がスタックにないという問題があると信じています....検証には時間がかかるでしょうが、それは私の問題かもしれません。 –