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