jeudi 22 septembre 2016

Add and remove event handler via reflection c#

Good day! My purpose is to implement class which will allow us subscribe and unsubscribe objects to(from) events. Here is the code of my class.

public static class EventSubscriber
{
    public static void AddEventHandler(EventInfo eventInfo, object item, Action action)
    {
        var parameters = GetParameters(eventInfo);
        var handler = GetHandler(eventInfo, action, parameters);
        eventInfo.AddEventHandler(item, handler);
    }

    public static void RemoveEventHandler(EventInfo eventInfo,
                        object item, Action action)
    {
        var parameters = GetParameters(eventInfo);
        var handler = GetHandler(eventInfo, action, parameters);
        eventInfo.RemoveEventHandler(item, handler);
    }

    private static ParameterExpression[] GetParameters(EventInfo eventInfo)
    {
        return eventInfo.EventHandlerType
          .GetMethod("Invoke")
          .GetParameters()
          .Select(parameter => Expression.Parameter(parameter.ParameterType))
          .ToArray();
    }

    private static Delegate GetHandler(EventInfo eventInfo,
                Action action, ParameterExpression[] parameters)
    {
        return Expression.Lambda(
            eventInfo.EventHandlerType,
            Expression.Call(Expression.Constant(action),
                      "Invoke", Type.EmptyTypes), parameters)
          .Compile();
    }
}

As you can see here are 2 public methods which actually subscribe and unsubscribe objects to(from) event. And here is the sample how I test it

class Program
{
    static void Main()
    {
        Test test = new Test();
        test.SubscribeTimer();
        while (true)
        {
            if(test.a == 10)
            {
                break;
            }
        }
        test.UnsubscribeTimer();
        while (true)
        {

        }
    }
}

class Test
{
    System.Timers.Timer timer;
    public int a = 0;

    public Test()
    {
        timer = new System.Timers.Timer(1000);
        timer.Start();
    }

    public void SubscribeTimer()
    {
        var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
        EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);
        EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerNotElapsed);
    }

    public void UnsubscribeTimer()
    {
        var eventInfo = typeof(System.Timers.Timer).GetEvent("Elapsed");
        EventSubscriber.AddEventHandler(eventInfo, timer, TimerNotElapsed);
        EventSubscriber.RemoveEventHandler(eventInfo, timer, TimerElapsed);
    }

    public void TimerElapsed()
    {
        Console.WriteLine("timer elapsed");
        a++;
    }

    public void TimerNotElapsed()
    {
        Console.WriteLine("timer not elapsed");
        a++;
    }
}

The expected behaviour of sample is that on the begining we will see the message "timer elapsed" every second, after 10-th second we should see only "timer not elapsed" and we do, but we still see "timer elapsed" too. This means that AddEventHandler method works, but RemoveEventHandler methods doesn't.

I would be very happy if you will help me. Thanks in advance.





Aucun commentaire:

Enregistrer un commentaire