在什么情况下从必要的事件中分离?

我不确定我是否完全清楚附加对象中的事件的含义。

这是我目前的理解,正确或精细:

1.不需要分离附加到本地类事件

例子:

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

public event EventHandler OnMyCustomEvent = delegate { };

我假设当你的对象被处理或被垃圾收集时,这些函数会被释放并自动从事件中分离出来。

2.必须分离附加到不再需要的对象(= null;)

示例:附加到计时器的Elapsed事件,您只响应一次。 我假设您需要将Timer存储在本地变量中,以便在事件触发后分离Elapsed事件。 因此,在本地方法范围内声明计时器会导致泄漏:

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

3.将本地对象中的事件附加到您的class级不需要处理?

例如,如果您有一个ObservableCollection,您可以创建,监视并让它们死掉。 如果使用本地私有函数附加到CollectionChanged事件,当您的类被垃圾收集时,此函数是否会解除分配,导致ObservableCollection也被释放?

我确定我有停止使用对象并且无法从事件中分离的地方(例如,我制作的计时器示例),所以我正在寻找关于它是如何工作的更清楚的解释。

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

  • 订阅活动时,活动的“所有者”(发布者)通常会保留对您订阅的代理人的引用。
  • 如果使用实例方法作为委托的操作,则委托具有对其“目标”对象的引用。

这意味着如果你写:

 publisher.SomeEvent += subscriber.SomeMethod; 

除非您稍后取消订阅,否则订阅subscriber将无法在publisher之前进行垃圾回收。

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

 publisher.SomeEvent += myDataTimer_Elapsed; 

相当于:

 publisher.SomeEvent += this.myDataTimer_Elapsed; 

假设它是一个实例方法。

由于事件订阅没有反向关系 – 换句话说,订阅者不会保持发布者的活力。

顺便提一下,请参阅我关于事件和代表的文章以获取更多信息。

其余的防止垃圾收集的引用还有一个可能很明显的效果,但是在这个post中还没有说明; 附加的事件处理程序也将被执行。

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

一段时间后,这导致每次引发特定事件时都会执行大量事件侦听器。 当大量“睡眠”实例突然醒来并尝试对同一输入采取行动时,这当然会导致严重的竞争条件。

简而言之; 如果你编写代码来挂钩一个事件监听器; 确保在不再需要时立即释放。 我几乎敢于承诺,它将在未来的某个时刻让你免于至少一次头痛。

您必须取消订阅活动的相关案例如下:

 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()相关的事件处理程序中分离B.DoSomething()

如果事件订阅行看起来像这样,你可能遇到同样的事情,当然:

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

现在它是一个挂钩的someOtherObject ,不能被垃圾收集。