通过反射 c# 添加和删除事件处理程序 [英] Add and remove event handler via reflection c#

查看:71
本文介绍了通过反射 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();
    }
}

正如您在此处看到的,有 2 个公共方法实际订阅和取消订阅对象到(来自)事件.这是我如何测试它的示例

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++;
    }
}

sample 的预期行为是,在开始时,我们将每秒看到消息timer elapsed",在第 10 秒之后,我们应该只看到timer not elapsed",我们看到了,但我们仍然看到timer elapsed""也.这意味着 AddEventHandler 方法有效,但 RemoveEventHandler 方法无效.

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 method doesn't.

如果你能帮助我,我会很高兴.提前致谢.

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

推荐答案

我认为是因为你每次都在创建一个新的处理程序:(与之前的处理程序不匹配,所以不能从调用列表)

I think it's because you are creating a new handler each time: (which doesn't match the previous handler, so can't be removed from the invocation list)

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

为什么要包装 Action?丢失参数?由于参数的原因,无法添加/删除 eventInfo.RemoveEventHandler(item, action);.如果要删除新生成的处理程序,则应在删除时返回该处理程序.

Why are you wrapping the Action? To lose the parameters? It is not possible to add/remove the eventInfo.RemoveEventHandler(item, action); because of the parameters. If you want to remove a newly generated handler, you should return that handler when you want to remove it.

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

public static void RemoveEventHandler(EventInfo eventInfo,
                    object item, Delegate handler)
{
    eventInfo.RemoveEventHandler(item, handler);
}

<小时>

var handler = EventSubscriber.AddEventHandler(eventInfo, timer, TimerElapsed);

EventSubscriber.RemoveEventHandler(eventInfo, timer, handler);

这篇关于通过反射 c# 添加和删除事件处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆