2012年3月19日星期一

如何获取事件的响应函数列表

很多对象实现了IDispose接口的, 例如Socket对象. 在使用后, 需要及时调用Dispose()方法销毁.

但是如果对象上的事件注册了事件响应函数, 那么就必须等待事件响应函数所在的对象回收以后, 它才能回收, 这个很容易导致程序出问题.

所以比较理想的方案是在调用Dispose()之前, 把时间的事件响应函数注销掉.  这个就ok了.

 

但是对象的事件响应函数可以添加多个, 而且一个事件可能在若干个对象中被注册了响应函数, 如何获取调用函数的列表呢, 然后住校呢.

 

<CLR VIA C#>的事件一章, 详细讲解了.net的事件是通过字段+方法来实现的. 也就是说, 事件会被翻译成一个对应的委托私有字段.

那么我们如果能够获取到委托的值, 就能获取到响应函数列表了.

 

static EventHandler<EventArgs> GetEventHandler(object classInstance, string eventName){    Type classType = classInstance.GetType();    FieldInfo eventField = classType.GetField(eventName, BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);    EventHandler<EventArgs> eventDelegate = (EventHandler<EventArgs>)eventField.GetValue(classInstance);    // eventDelegate will be null if no listeners are attached to the event    if (eventDelegate == null)    {        return null;    }    return eventDelegate;}

 

这段代码就是获取事件对应委托的.

获取到委托以后, 调用委托的GetInvocationList()方法, 就可以获得响应函数列表了, 然后强制转换成对应的事件类型, 然后对事件执行-=操作, 就可以了.
代码如下:

           Delegate[] dgs = eventDelegate.GetInvocationList();            foreach (Delegate dg in dgs)            {                EventHandler<EventArgs> eh = (dg as EventHandler<EventArgs>);                host.TestEvent -= eh;            } 

不过需要注意的是: .net中, 还提供属性事件: 也即是会被.net翻译成属性的事件, 具体可以看MSDN中对于事件的介绍中, 专门有一节介绍了属性事件.

一般属性事件适用于WinForm程序.

获取属性事件的响应函数列表的过程类型, 只是把:

FieldInfo eventField = classType.GetField(eventName, BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);

替换成:

PropertyInfo propertyInfo = (typeof(EventHost)).GetProperty(eventNameBindingFlags.Instance | BindingFlags.NonPublic );

其实就是从获取字段信息变成获取属性信息.


如何获取事件的响应函数列表

TAG: