C# 在什么情况下需要从事件中分离?
我不确定我是否完全清楚在对象中附加事件的含义 这是我目前的理解,正确或详细: 1。附加到本地类事件不需要分离 示例:C# 在什么情况下需要从事件中分离?,c#,.net,events,event-handling,C#,.net,Events,Event Handling,我不确定我是否完全清楚在对象中附加事件的含义 这是我目前的理解,正确或详细: 1。附加到本地类事件不需要分离 示例: this.Closing+=new System.ComponentModel.CancelEventHandler(MainWindow\u Closing) 公共事件事件处理程序OnMyCustomEvent=delegate{} 我假设当您的对象被释放或垃圾回收时,函数被释放并将自动从事件中分离 2。附加到不再需要的对象(=null;)必须从中分离 示例: 附加到计时器的已
this.Closing+=new System.ComponentModel.CancelEventHandler(MainWindow\u Closing)代码>
公共事件事件处理程序OnMyCustomEvent=delegate{}代码>
我假设当您的对象被释放或垃圾回收时,函数被释放并将自动从事件中分离
2。附加到不再需要的对象(=null;)必须从中分离
示例:
附加到计时器的已用事件,您只响应一次。我假设您需要将计时器存储在一个局部变量中,这样您就可以在事件触发后分离经过的事件。因此,在这样的本地方法范围内声明计时器将导致泄漏:
System.Timers.Timer myDataTimer=新系统.Timers.Timer(1000);
myDataTimer.Appeased+=新系统.Timers.ElapsedEventHandler(myDataTimer_Appeased)代码>
3。将本地对象中的事件附加到类不需要处理?
例如,如果您有一个可观察的集合,您可以创建、监视并让其消亡。如果您使用本地私有函数附加到CollectionChanged事件,那么当您的类被垃圾收集时,该函数是否会取消分配,从而导致ObservableCollection也被释放
我确信我有一些地方已经停止使用对象,并且无法从事件中分离(例如,我制作的计时器示例),因此我正在寻找一个更清晰的解释,说明这是如何工作的。我认为你让它变得比需要的更复杂。你只需要记住两件事:
- 订阅事件时,事件的“所有者”(发布者)通常会保留对您订阅的代理的引用
- 如果使用实例方法作为委托的操作,则委托具有对其“目标”对象的引用
这意味着如果你写:
publisher.SomeEvent += subscriber.SomeMethod;
然后,除非您稍后取消订阅,publisher
之前,订阅者将没有资格进行垃圾收集
请注意,在许多情况下,订户
只是这个
:
publisher.SomeEvent += myDataTimer_Elapsed;
相当于:
publisher.SomeEvent += this.myDataTimer_Elapsed;
假设它是一个实例方法
仅仅由于事件订阅,不存在反向关系-换句话说,订阅者不会使发布者保持活动状态
顺便说一下,有关更多信息,请参见。您必须取消订阅活动的相关案例如下:
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
挂在钩子上,无法进行垃圾收集。阻止垃圾收集的其余引用还有一个效果,可能很明显,但在此线程中尚未说明;附加的事件处理程序也将被执行
我已经经历过好几次了。一个是当我们有一个应用程序,它运行的时间越长,速度就越慢。应用程序通过加载用户控件以动态方式创建用户界面。容器使用户控件订阅环境中的某些事件,其中一个在控件“卸载”时没有取消订阅
一段时间后,这导致每次引发特定事件时都会执行大量事件侦听器。当然,当大量“睡眠”实例突然醒来并试图对同一输入采取行动时,这会导致严重的竞争状况
简言之;如果您编写代码来连接事件侦听器;确保在不再需要时尽快发布。我几乎敢保证,在将来的某个时候,它至少会让你免于一次头痛。你说得对,我把事情复杂化了。在寻找示例时,几乎所有的事件都与事件分离,这只能让我相信订阅者可以让发布者存活。愚蠢的问题:这是否意味着如果发布者订阅订阅者上的事件,那么这两个事件都不能/将不会被收集?不,这意味着有一个循环引用——一旦没有其他根引用指向它们中的任何一个,它们都将符合GC的条件。