Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在什么情况下需要从事件中分离?_C#_.net_Events_Event Handling - Fatal编程技术网

C# 在什么情况下需要从事件中分离?

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;)必须从中分离 示例: 附加到计时器的已

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

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

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

示例:

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的条件。