2010-05-27 59 views
9

最近我一直在研究内存管理,并且一直在研究如何管理事件,现在,我看到了事件订阅的显式添加/删除语法。显式事件添加/删除,误解?

我认为这很简单,添加/删除只允许我执行其他逻辑,当我订阅和取消订阅?我是否明白了,还是有更多呢?

另外,虽然我在这里,任何清理我的事件处理建议/最佳做法。

回答

3

添加/删除语法通常用于将事件实现“转发”到另一个类。

清理订阅(不是“事件句柄”)最好通过执行IDisposable来完成。

更新:对于哪个对象应该实现IDisposable有一些变化。 Rx团队从设计角度做出了最好的决定:订阅本身是IDisposable。常规.NET事件没有表示订阅的对象,因此选择是在发布者(定义事件的类)和订阅者(​​通常是包含正在订阅的成员函数的类)之间进行的。尽管我的设计本能更愿意让用户IDisposable,但大多数真实世界的代码使得发布者IDisposable:这是一个更容易的实现,并且可能存在没有实际订阅者实例的情况。

(也就是说,如果代码实际上清理事件订阅的。大多数代码没有。)

+0

哈,我在与同事交谈时将它们称为订阅,但当我发布一个问题时,我使用了错误的术语。 感谢您的澄清。 – Hammerstein 2010-05-27 18:58:45

6

是,在添加/删除语法,让你实现你自己的订阅逻辑。当你将它们排除(事件的标准符号)时,编译器会生成标准实现。这就像自动属性。

在下面的示例中,事件1和事件2之间没有真正的区别。

public class Foo 
{ 
    private EventHandler handler; 
    public event EventHandler Event1 
    { 
    add { handler += value; } 
    remove { handler -= value; } 
    } 

    public event EventHandler Event2; 
} 

但是,这是从“清理”处理一个独立的主题。订阅类应该做退订。出版社对此非常不利。
想象一下,可以“清理”其事件的订阅列表的类。只有当它被释放时它才会明智地做到这一点,然后它不太可能有生产力,因为处置后的类通常在被处置后不久就变得可收集。

+1

我相信最终用户不能这样做:'Foo foo = ...; foo.Event1(sender,e);'但可以做'foo.Event2(null,null);'。 – user7116 2010-05-27 19:11:26

+0

感谢您的示例和澄清。我以为我拥有它,但我一直在想它! 我会在一个单独的问题上发布我关于内存管理的问题,因为我认为我想问的更多。 – Hammerstein 2010-05-27 19:15:33

+0

我错了,在这两种情况下都会收到错误消息,但在第二种情况下会收到另一个错误消息:错误CS0070:事件'Program.Foo.Event2'只能出现在+ =的左侧或 - =(从“Program.Foo”类型内使用)除外。 – user7116 2010-05-27 19:17:06

9

添加/删除特性基本上都采用了设置/获取与其他成员属性的相同的逻辑的。 它允许你创建一些额外的逻辑,同时注册了一个事件,封装事件本身。

为什么要做这件事的一个很好的例子就是在不需要的时候停止额外的计算(没人在听这个事件)。

例如,让我们说,事件是由定时器触发,而我们不希望,如果没有一个被注册到该事件的定时器工作:

private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); 
private EventHandler _explicitEvent; 
public event EventHandler ExplicitEvent 
{ 
    add 
    { 
     if (_explicitEvent == null) timer.Start(); 
     _explicitEvent += value; 
    } 
    remove 
    { 
     _explicitEvent -= value; 
     if (_explicitEvent == null) timer.Stop(); 
    } 
} 

你可能想用对象锁定添加/删除(一个事后想法)...