C#事件处理程序订阅管理

4

我有一个类:

public abstract class BaseComponent { ... }

在该类的构造函数中,我们订阅一个事件处理程序,例如:
protected ObjectWithEventHandler eventObject { get; private set; }

public BaseComponent (ObjectWithEventHandler obj)
{
    eventObject = obj;
    eventObject.ChangedEvent += new EventHandler(eventObject_OnChangedEvent );
}

protected void eventObject_OnChangedEvent (object sender, EventArgs e) { ... }

当涉及 EventHandler 的订阅和取消订阅时,是否有任何硬性规定?

提供一些清理代码来取消从 EventHandler 订阅的函数是否被视为良好的实践?例如,实现 IDisposable 并从 EventHandler 取消订阅?

或者我是在过度担心?


我相信你不需要担心这个问题。在 C# 中,当实例被垃圾收集(即不再在范围内或实例不再被任何其他地方引用)时,它会清除所有事件引用。 - musefan
@musefan,这个故事有点复杂:你需要考虑涉及对象的生命周期。 - flq
3个回答

3
只要在一个BaseComponent类中创建了暴露事件(eventObject)的对象 - 您可以忽略显式取消订阅,因为它将自动进行垃圾回收,但显式取消订阅是一个好的实践方式。
但是,如果您订阅了由注入到BaseComponent中的外部对象公开的事件,则应在BaseComponent类中实现IDisposable,并在Dispose()方法中进行清理。

3
如果您完全掌控BaseComponent的使用,并且您知道与BaseComponent的生命周期相比,EventObject的生命周期更短或相等*,则可以跳过取消订阅代码。
在所有其他情况下,我会包括它。在这种情况下,实现IDisposable是很好的风格。 * ) 实际上,您将eventObject的生命周期耦合到BaseComponent上,因此它不能更短,但当两者一起超出范围时,它仍可能相等。

1

如果有可能事件对象的实例比派生自BaseComponent类的实例更长寿,那么您应该提供某种方式来显式触发取消订阅。否则,您将阻止组件的垃圾回收,因为eventObject持有对它的引用。

实现IDisposable()是一种很好的方法,只要您可以确保有一些代码实际调用它。finalizer不会调用Dispose(),因为只要它订阅了eventObject.ChangedEvent并且eventObject仍然存在,垃圾收集器就不会尝试清理您的组件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接