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

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

问题描述:

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

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

但它确实是更好地使客户从你的事件退订。

+1

在C#中无法将事件设置为null。 – 2011-05-25 23:35:50

+8

事实上,如果你是在声明事件的类内部的话,这是可能的。 – 2011-05-26 03:03:46

+1

你是对的。 – 2011-05-31 17:29:15

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

这通常用于解决客户“忘记”退订.NET事件的问题,所以它听起来像这可能很适合您的问题。

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

如果事件源在侦听器之前死亡,则不会阻止稍后收集侦听器,此时将其所有其他引用都设置为空。

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

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

你可以使事件处理函数无效,但是在它的所有者被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