铁血规则:事件预订与取消预订
2011-04-07 17:19
134 查看
在编码的时候,我们经常预订某个事件来处理它,但很少取消事件的预订,这种做法可能导致程序在运行时出现一些异常。
如果你的某个用于处理事件的对象不是在运行期内永久存在的(比如,不是Singleton对象),那么请记住一条规则:在该对象(事件预订者)的生命周期中只要预订了其他对象(事件发布者)的事件,那么在该对象释放时,一定要取消这些事件的预订。否则,在预订者被释放后,发布者仍然保持着预订者的引用,在对应的事件被触发时,发布者仍然会持有预订者的引用(导致内存泄露),并且调用预订者的处理函数,而由于预订者已经被释放,所以可能引发莫名其妙的问题。(这条规则很早就总结出来了,最近却忘记了,以至于浪费了半天的时间来跟踪一个奇怪的现象。以此记录作为前车之鉴,呵呵)
实践这条规则很简单,一般这样做就可以了:
(1)在预订者的构造函数或初始化函数中预订事件。
(2)在预订者的析构函数或Dispose方法中取消事件预订。
比如:
public class Publisher
{
public event CbGeneric SomeEvent;
}
public class Subscriber :IDisposable
{
private Publisher publisher;
public Subscriber(Publisher _publisher)
{
this.publisher = _publisher ;
//预订事件
this.publisher.SomeEvent += new CbGeneric(publisher_SomeEvent);
}
void publisher_SomeEvent()
{
//处理事件
}
public void Dispose()
{
//取消预订
this.publisher.SomeEvent -= new CbGeneric(publisher_SomeEvent);
}
}
特别是当预订者是自定义的windows控件时(从Control类继承),我们可以在其自身的Disposed事件中,来取消对发布者的事件预订。当包含该控件对象的宿主Form被关闭时,控件对象也会被释放,这可能是一个很隐蔽的问题,以至于我们忘了在控件被释放时取消必须的事件预订。
我们也许想到,如果发布者与预订者的生命周期是完全相同的,是不是就不需要取消预订了?大多数情况下是可以的,但是你要保证你的发布者对象在被释放后,是否还被其他的对象持有引用,这样也可能会导致内存泄露以及其他问题。所以,我们建议,既然预订了事件,就请在预订者被释放时,取消这些预订。
如果你的某个用于处理事件的对象不是在运行期内永久存在的(比如,不是Singleton对象),那么请记住一条规则:在该对象(事件预订者)的生命周期中只要预订了其他对象(事件发布者)的事件,那么在该对象释放时,一定要取消这些事件的预订。否则,在预订者被释放后,发布者仍然保持着预订者的引用,在对应的事件被触发时,发布者仍然会持有预订者的引用(导致内存泄露),并且调用预订者的处理函数,而由于预订者已经被释放,所以可能引发莫名其妙的问题。(这条规则很早就总结出来了,最近却忘记了,以至于浪费了半天的时间来跟踪一个奇怪的现象。以此记录作为前车之鉴,呵呵)
实践这条规则很简单,一般这样做就可以了:
(1)在预订者的构造函数或初始化函数中预订事件。
(2)在预订者的析构函数或Dispose方法中取消事件预订。
比如:
public class Publisher
{
public event CbGeneric SomeEvent;
}
public class Subscriber :IDisposable
{
private Publisher publisher;
public Subscriber(Publisher _publisher)
{
this.publisher = _publisher ;
//预订事件
this.publisher.SomeEvent += new CbGeneric(publisher_SomeEvent);
}
void publisher_SomeEvent()
{
//处理事件
}
public void Dispose()
{
//取消预订
this.publisher.SomeEvent -= new CbGeneric(publisher_SomeEvent);
}
}
特别是当预订者是自定义的windows控件时(从Control类继承),我们可以在其自身的Disposed事件中,来取消对发布者的事件预订。当包含该控件对象的宿主Form被关闭时,控件对象也会被释放,这可能是一个很隐蔽的问题,以至于我们忘了在控件被释放时取消必须的事件预订。
我们也许想到,如果发布者与预订者的生命周期是完全相同的,是不是就不需要取消预订了?大多数情况下是可以的,但是你要保证你的发布者对象在被释放后,是否还被其他的对象持有引用,这样也可能会导致内存泄露以及其他问题。所以,我们建议,既然预订了事件,就请在预订者被释放时,取消这些预订。
相关文章推荐
- 铁血规则:事件预订与取消预订[转]
- GridView行编辑、更新、取消、删除事件用法
- C# 委托事件的另类取消方法
- event事件对象 兼容写法:var oEvent=ev||event;和取消事件冒泡
- 24、规则流中的事件说明
- flex中event.preventDefault()方法取消事件的默认行为
- μCOS-II系统之事件(event)的使用规则及Semaphore的互斥量用法
- makefile中重载与取消隐藏规则示例
- 取消事件冒泡(大小DIV)
- 取消事件的冒泡
- 取消 nestedlist 点击弹出 detailcard 事件,主要就是把detailcard 设置为null 即可;
- Android自定义控件实现不规则区域点击事件
- 取消事件传播 兼容ie和所有浏览器 preventDefault returnValue stopPropagation cancelBubble addEventListener attachEvent
- Dom对象事件注册和取消(addEventListener/attachEvent)
- js checkbox全选和取消的事件
- jquery中取消绑定事件unbind不起作用
- -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event(实现不规则点击,事件分发)
- event.preventDefault() 取消事件的默认行为。
- JQuery事件e参数的方法preventDefault()取消默认行为
- js取消事件冒泡和阻止事件的默认行为(兼容写法)