Call a method when a generic event occurs

自闭症网瘾萝莉.ら 提交于 2020-01-07 01:51:17

问题


I'm facing a problem when trying to implement a call to a method fired up by an event which should be defined during run-time. I found this answer:

Redirecting to a dynamic method from a generic event handler

and implemented that solution, but I keep getting an exception when the method to call is an instance one, not static. Here is my partial code:

public class Operation
{
    public bool EventFired 
    {
        get { return _eventFired; }
    }

    private bool _eventFired = false;

    public void Execute(object source, string EventName)
    {
        EventInfo eventInfo = source.GetType().GetEvent(EventName);
        Delegate handler = null;

        Type delegateHandler = eventInfo.EventHandlerType;
        MethodInfo invokeMethod = delegateHandler.GetMethod("Invoke");
        ParameterInfo[] parms = invokeMethod.GetParameters();

        Type[] parmTypes = new Type[parms.Length];

        for (int i = 0; i < parms.Length; i++)
            parmTypes[i] = parms[i].ParameterType;

        DynamicMethod customMethod = new DynamicMethod
            (
            "TempMethod",
            invokeMethod.ReturnType,
            parmTypes,
            typeof (Operation).Module
            );

        MethodInfo inf = typeof (Operation).GetMethod("SetFlag", BindingFlags.Instance | BindingFlags.Public);

        ILGenerator ilgen = customMethod.GetILGenerator();
        ilgen.Emit(OpCodes.Ldarg_0);
        ilgen.Emit(OpCodes.Call, inf);
        ilgen.Emit(OpCodes.Ret);

        //handler = _customMethod.CreateDelegate(delegateHandler);          // This works if I change SetFlag() to static 

        handler = customMethod.CreateDelegate(delegateHandler, this);       // I get an ArgumentException at this point: 
                                                                            //Cannot bind to the target method because its signature 
                                                                            //or security transparency is not compatible with that of the delegate type.   



        eventInfo.AddEventHandler(source, handler);
    }

    /// <summary>Signals that the event has been raised.</summary>
    public void SetFlag()
    {
        _eventFired = true;
    }

}

I can't find a way to get rid of that exception, the code works fine if I turn SetFlag() method to static, but that's not what I need. Any suggestions would be very appreciated. Thanks in advance.


回答1:


I finally managed to resolve the problem by slightly modifying the DynamicMethod definition, as described in this answer:

Reference 'this' in dynamic event handler

If I add my class type as first value in the Type array, which is then passed as parameter to the DynamicMethod, the delegate is correctly created and it works with instance methods!

public class Operation
{
    public bool EventFired 
    {
        get { return _eventFired; }
    }

    private bool _eventFired = false;

    public void Execute(object source, string EventName)
    {
        EventInfo eventInfo = source.GetType().GetEvent(EventName);
        Delegate handler = null;

        Type delegateHandler = eventInfo.EventHandlerType;
        MethodInfo invokeMethod = delegateHandler.GetMethod("Invoke");
        ParameterInfo[] parms = invokeMethod.GetParameters();

        Type[] parmTypes = new Type[parms.Length + 1];

        parmTypes[0] = this.GetType();  //First parameter is this class type.

        for (int i = 0; i < parms.Length; i++)
            parmTypes[i + 1] = parms[i].ParameterType;

        DynamicMethod customMethod = new DynamicMethod
                                    (
                                        "TempMethod",
                                        invokeMethod.ReturnType,
                                        parmTypes
                                    );

        MethodInfo inf = typeof (Operation).GetMethod("SetFlag", BindingFlags.Instance | BindingFlags.Public);

        ILGenerator ilgen = customMethod.GetILGenerator();
        ilgen.Emit(OpCodes.Ldarg_0);
        ilgen.Emit(OpCodes.Call, inf);
        ilgen.Emit(OpCodes.Ret);

        handler = customMethod.CreateDelegate(delegateHandler, this);      

        eventInfo.AddEventHandler(source, handler);
    }

    /// <summary>Signals that the event has been raised.</summary>
    public void SetFlag()
    {
        _eventFired = true;
    }

}


来源:https://stackoverflow.com/questions/34069482/call-a-method-when-a-generic-event-occurs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!