【问题标题】:C# How to unsubscribe all event handlers from a given event?C#如何取消订阅给定事件的所有事件处理程序?
【发布时间】:2010-03-28 13:19:18
【问题描述】:

有没有一种简单的方法来遍历订阅给定事件的所有处理程序?我的问题是客户订阅但忘记取消订阅,因此发生内存泄漏。我需要一种方法让对象在 Dispose 方法中断开其事件的所有处理程序,这样就不会发生泄漏 - 至少不是因为事件。

【问题讨论】:

    标签: c# events memory-leaks


    【解决方案1】:

    为您的事件设置 null:MyEvent = null;

    但最好让客户退订您的活动。

    【讨论】:

    • 在 C# 中无法将事件设置为 null。
    • 实际上是有可能的,如果你在声明事件的类里面。
    • MyEvent = new MyEvent()不是更好吗?那么当你再次订阅时,你不会得到空异常。
    • @Mateusz:如果没有人订阅,则事件字段为空,触发事件的代码在访问事件之前始终应进行空检查
    • @Mateusz 不管怎样,Adi 提到他想在 Dispose 方法中取消订阅。所以他不会再使用这个对象了。
    【解决方案2】:

    另一种方法是使用所谓的“弱委托”模式。当您使用此技术时,事件仅使用 WeakReference 引用客户端,这不会将它们保存在内存中。当客户端不再被应用程序的其他部分引用时,它们将被垃圾收集(并且处理程序也可以在客户端被收集时自动取消注册)。

    这通常用于解决客户端“忘记”取消订阅 .NET 事件的问题,因此听起来这可能非常适合您的问题。

    【讨论】:

      【解决方案3】:

      仅当另一个对象(侦听器)在您的对象(事件源)之前死亡时才会发生内存泄漏。在这种情况下,事件源仍然保留对侦听器的引用,这会阻止侦听器被收集。当事件源死亡时,也可能会收集未订阅的侦听器。

      如果事件源在侦听器之前死亡,这不会阻止侦听器稍后被收集,此时对它的所有其他引用都设置为 null。

      这意味着,事件源的 Dispose 方法不是解决这个问题的正确地方。它只能在侦听器代码中解决。简单地说,除了要求客户编写干净的代码之外,您什么也做不了。

      【讨论】:

        【解决方案4】:

        在撰写本文时,最准确的答案是最不受欢迎的。

        您可以取消事件处理程序,但是在它的所有者被 zapped 之后无论如何它都会被 zapped - 超级整洁并没有错,但就像 Alex 所说,这不是问题所在。

        Adi 的源类将允许在收集它自己时收集监听对象,这是毫无疑问的。所以问题是 Adi 的源对象一直保持打开状态,可能来自他客户代码中的一些长引用链。

        以下博客文章还介绍了 Adi 描述的解决方案,并解释了为什么它是不必要的。

        http://weblogs.sqlteam.com/mladenp/archive/2007/10/24/C-Care-about-Event-Memory-Leaks-with-Delegate.GetInvocationList.aspx

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-15
          • 2021-03-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多