C#如何取消订阅特定事件中的所有事件处理程序?

时间:2010-03-28 13:19:18

标签: c# events memory-leaks

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

4 个答案:

答案 0 :(得分:12)

将null设置为您的活动:MyEvent = null;

但让客户取消订阅活动确实更好。

答案 1 :(得分:9)

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

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

答案 2 :(得分:7)

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

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

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

答案 3 :(得分:1)

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

你可以使事件处理程序无效,但是在它的所有者被摧毁之后无论如何都会被破坏 - 这是非常整洁的错误,但就像亚历克斯所说,这不是问题所在。

Adi的源类将允许在收集侦听对象时收集它,毫无疑问。所以问题是Adi的源对象是保持开放的,可能来自客户代码中的一些长引用。

以下博客文章还介绍了Adi正在解释的解决方案,并解释了为什么没有必要。

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