In dem Bemühen, F # und .Net zu lernen, habe ich mit dem zu veröffentlichenden DLR gespielt.Delegate/DLR Lambdas verwenden, um Instanzmethoden zu überschreiben?
Zu diesem Zweck habe ich mit Reflektion herumgespielt, um ein grundlegendes Typsystem zu implementieren, das sich gut in die clr integriert. Während ich in der Lage bin, einen einfachen Typ zu instanziieren, der Object erweitert, erhalte ich beim Aufruf der von ihm definierten Methode einen Fehler.
Da am Ende des Tages DLR LambdaExpressions zu Delegaten kompilieren, was ich tue, ist generierte MethodInfo aus dem generierten Delegaten und rufen Sie es auf, den Stapel mit den Argumenten der generierten Methode auffüllen. Dann gib es zurück. An diesem Punkt bekomme ich meinen Fehler.
Hier ist mein Code:
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)|])
Hier ist mein Fehler, von 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
Jede Hilfe oder Anregungen geschätzt-ich bin so mein Fehler ein bisschen ein .Net newb würde kann einfach sein.
Mike Kohout
Ein Schuss in die Dunkelheit - erhalten Sie das gleiche Verhalten beim Kompilieren mit fsc.exe? Die MethodAccessException schlägt vor, dass etwas nicht öffentlich ist, aber all dein Code scheint öffentliche Methoden zu generieren, also bin ich mir nicht sicher, warum das passiert ... – Brian
Danke für den Vorschlag, Brian, aber es sieht so aus, als würde es immer noch passieren. Danach mit fsc/VS2008 kompilieren, erhalte ich diesen (über VS2008 Debugging-„Ausnahme Detail“ Bereich): System.Reflection.TargetInvocationException wurde nicht behandelt Nachricht: Exception durch das Ziel für einen Aufruf ausgelöst wurde. –
Ich glaube, das Problem ist, dass das Delegat-Objekt selbst nicht auf dem Stapel ist .... es wird einige Zeit dauern, um zu überprüfen, aber ich denke, dass das mein Problem sein könnte. –