2009-04-21 67 views
16

我不确定是否完全清楚附着在对象中的事件的影响。在什么情况下脱离必要的事件?

这是我目前的理解,正确的或复杂:

1.附加到地方级赛事中不需要拆卸

例子:

this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);

public event EventHandler OnMyCustomEvent = delegate { };

我假设当你的ob物品被丢弃或垃圾收集,功能被解除分配并且会自动脱离事件。

2.附加到对象,你不再需要的(= NULL;)必须从

实例分离: 附加到定时器的经过的事件,你只响应一次。我假设你需要将Timer存储在本地变量中,以便在事件触发后分离Elapsed事件。因此,宣布计时器在本地方法的范围,像这样将导致泄漏:

System.Timers.Timer myDataTimer = new System.Timers.Timer(1000); myDataTimer.Elapsed += new System.Timers.ElapsedEventHandler(myDataTimer_Elapsed);

3.附加到事件在本地对象类并不需要处置?

例如,如果您有一个ObservableCollection,您创建,监视并让它死亡。如果使用本地私有函数附加到CollectionChanged事件,那么当您的类被垃圾回收时,此函数是否不会释放,导致ObservableCollection也被释放?

我确定我有地方我已经停止使用对象,并未能从事件(例如,我做的定时器例子)分离,所以我正在寻找一个更清晰的解释如何工作。

回答

22

我认为你让它比它需要更复杂。你只需要记住两件事:

  • 当你订阅一个事件时,事件的“所有者”(发布者)通常保持对你订阅的委托的引用。
  • 如果您使用实例方法作为委托的操作,那么委托会引用其“目标”对象。

这意味着,如果你写:

publisher.SomeEvent += subscriber.SomeMethod; 

然后subscriber将没有资格进行垃圾回收之前publisher是,除非你以后退订。

注意,在许多情况下,subscriber只是this

publisher.SomeEvent += myDataTimer_Elapsed; 

等同于:

publisher.SomeEvent += this.myDataTimer_Elapsed; 

假定它是一个实例方法。

没有只是由于事件订阅的逆向关系 - 换句话说订阅者不会让发布者保持活跃状态​​。

请参阅my article on events and delegates了解更多信息,顺便说一下。

+0

你完全正确,我过于复杂的事情。在寻找示例时,几乎所有人都表现出与事件分离,这只会让我相信订户可以让发布商保持活力。 – 2009-04-21 19:38:31

1

,你必须从事件退订相关的情况是这样的:

public class A 
{ 
    // ... 
    public event EventHandler SomethingHappened; 
} 

public class B 
{ 
    private void DoSomething() { /* ... */ } // instance method 

    private void Attach(A obj) 
    { 
     obj.SomethingHappened += DoSomething(); 
    } 
} 

在这种情况下,当你处理一个B的,仍然会有来自obj的悬空参考吧事件处理器。如果您想要回收B的内存,则需要首先从相关事件处理程序中分离B.DoSomething()

如果事件订阅行这个样子,当然,你可能会遇到同样的事情:

obj.SomethingHappened += someOtherObject.Whatever.DoSomething(); 

现在是someOtherObject这对钩和垃圾回收是不可能的。

3

其余的引用阻止垃圾回收有一个更多的效果,可能是显而易见的,但这个线程中还没有说明;附加的事件处理程序也将被执行。

我已经经历过几次。一个是当我们有一个应用程序越来越慢,运行时间越来越慢。应用程序通过加载用户控件以动态方式创建用户界面。容器使用户控件订阅了环境中的某些事件,并且其中的一个未在控件“卸载”时取消订阅。

过了一段时间,这导致大量的事件侦听器在每次引发特定事件时都被执行。这当然会导致严重的竞争条件,当很多“睡眠”实例突然醒来并尝试对相同的输入进行操作时。

总之;如果你编写代码来连接一个事件监听器,确保您在不再需要时立即发布。我几乎敢承诺,它将在未来的某个时刻至少让你至少头疼一次。

相关问题