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 + "  执行一次");
        });
    } 
  • 相关阅读:
    android 75 新闻列表页面
    android 74 下载文本
    android 73 下载图片
    android 72 确定取消对话框,单选对话框,多选对话框
    android 71 ArrayAdapter和SimpleAdapter
    android 70 使用ListView把数据显示至屏幕
    maven如何将本地jar安装到本地仓库
    Centos6.7搭建ISCSI存储服务器
    解决maven打包编译出现File encoding has not been set问题
    MySQL 解决 emoji表情 的方法,使用utf8mb4 字符集(4字节 UTF-8 Unicode 编码)
  • 原文地址:https://www.cnblogs.com/icyJ/p/Reflection.html
Copyright © 2011-2022 走看看