.NET基础扩展系列-如何获取事件的响应函数列表

时间:2023-02-04 00:10:27

    很多对象实现了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 ); 

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