zoukankan      html  css  js  c++  java
  • c# 利用反射清除事件

    控件的事件清除,除了-=,就只能依靠反射来执行了。

    /// <summary>
    /// 清除一个对象的某个事件所挂钩的delegate
    /// </summary>
    /// <param name="ctrl">控件对象</param>
    /// <param name="eventName">事件名称,默认的</param>
    public static void ClearEvents(this object ctrl, string eventName = "_EventAll")
    {
        if (ctrl == null) return;
        BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Static;
        EventInfo[] events = ctrl.GetType().GetEvents(bindingFlags);
        if (events == null || events.Length < 1) return;
    
        for (int i = 0; i < events.Length; i++)
        {
            try
            {
                EventInfo ei = events[i];
                //只删除指定的方法,默认是_EventAll,前面加_是为了和系统的区分,防以后雷同
                if (eventName != "_EventAll" && ei.Name != eventName) continue;
    
                /********************************************************
                 * class的每个event都对应了一个同名(变了,前面加了Event前缀)的private的delegate类
                 * 型成员变量(这点可以用Reflector证实)。因为private成
                 * 员变量无法在基类中进行修改,所以为了能够拿到base 
                 * class中声明的事件,要从EventInfo的DeclaringType来获取
                 * event对应的成员变量的FieldInfo并进行修改
                 ********************************************************/
                FieldInfo fi = ei.DeclaringType.GetField("Event" + ei.Name, bindingFlags);
                if (fi != null)
                {
                    // 将event对应的字段设置成null即可清除所有挂钩在该event上的delegate
                    fi.SetValue(ctrl, null);
                }
            }
            catch { }
        }
    }

    当前使用环境.net 4.0。参考了很多其他人的代码,有三个地方值得注意。

    一个是eventName,GetField的时候在原来的Name前面加"Event"前缀。这个可能在不同的.net版本不一样,出现过三种:eventName,"Event"+eventName, "Event_" + controlType.Name + eventname.

    第二个:BindingFlags。尽量用Public | NonPublic | Instance | IgnoreCase | Static。

    第三:GetField的执行对象用EventInfo.DeclaringType,否则有可能继承的类获取不到数据。

    补充一个测试。下面的代码中Button会执行三次-=然后+=,但是每次的对象都是重新new的。三次绑定后,点击button1时,只执行一次输出。

    public Form1()
    {    
        this.Load += (a, b) =>
        {
            new Thread(new ThreadStart(() =>
            {
                int i = 0;
                while (true)
                {
                    if (button1.InvokeRequired) button1.Invoke(new Action(ReBindEvent));
                    else ReBindEvent();
                    Thread.Sleep(100);
                    i++;
                    if (i >= 3) break;
                }
            })).Start();
        };
    }
    
    void ReBindEvent()
    {
        button1.Click -= GetClickHandle();
        button1.Click += GetClickHandle();
    }
    
    EventHandler GetClickHandle()
    {
        return new EventHandler((a, b) =>
        {
            Console.WriteLine(DateTime.Now + "  执行一次");
        });
    } 
  • 相关阅读:
    ES6
    JavaScript小练习2
    JavaScript实现多重继承
    一个定高,一个高度自适应的布局
    实例教程:1小时学会Python(转)
    备份文件的python脚本(转)
    Python2.5/2.6实用教程:基础篇(转)
    Python 读写 Excel(转)
    python实用技巧 : Filtering os.walk(转)
    Python:文件操作技巧(File operation)(转)
  • 原文地址:https://www.cnblogs.com/icyJ/p/Reflection.html
Copyright © 2011-2022 走看看