代码之家  ›  专栏  ›  技术社区  ›  Will Eddins ianpoley

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

  •  16
  • Will Eddins ianpoley  · 技术社区  · 17 年前

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

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

    示例:

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

    public event EventHandler OnMyCustomEvent = delegate { };

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

    示例: 附加到计时器的已用事件,您只响应一次。我假设您需要将计时器存储在一个局部变量中,这样您就可以在事件触发后分离经过的事件。因此,在这样的本地方法范围内声明计时器将导致泄漏:

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

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

    例如,如果您有一个可观察的集合,您可以创建、监视并让其消亡。如果您使用本地私有函数附加到CollectionChanged事件,那么当您的类被垃圾收集时,该函数是否会取消分配,从而导致ObservableCollection也被释放?

    3 回复  |  直到 17 年前
        1
  •  23
  •   Jon Skeet    17 年前

    我觉得你把事情弄得比实际需要的更复杂了。你只需要记住两件事:

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

    这意味着如果你写:

    publisher.SomeEvent += subscriber.SomeMethod;
    

    然后 subscriber publisher 除非你以后退订。

    注意,在许多情况下, 订阅人 this :

    publisher.SomeEvent += myDataTimer_Elapsed;
    

    publisher.SomeEvent += this.myDataTimer_Elapsed;
    

    假设它是一个实例方法。

    仅由于事件订阅而导致的反向关系-换句话说,订阅服务器不会使发布服务器保持活动状态。

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

        2
  •  3
  •   Fredrik Mörk    17 年前

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

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

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

    简言之如果您编写代码来连接事件侦听器;确保在不再需要时尽快发布。我几乎敢保证,在将来的某个时候,它至少会让你免于一次头痛。

        3
  •  1
  •   mqp    17 年前

    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.DoSomething() 首先从相关的事件处理程序。

    当然,如果事件订阅行如下所示,您可能会遇到同样的问题:

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

    someOtherObject 那是挂在钩上的,不能被垃圾收集。