我正在研究如何正确创建弱引用事件处理程序。由于WPF已经有了避免事件内存泄漏的解决方案,我对"WeakEventManager"类进行了反编译,并花了一些时间对其进行了分析
正如我所发现的,"WeakEventManager"类依赖于创建和存储对目标对象以及事件处理程序委托的弱引用。以下是一些代码段:
this._list.Add(new WeakEventManager.Listener(target, handler));
public Listener(object target, Delegate handler)
{
this._target = new WeakReference(target);
this._handler = new WeakReference((object) handler);
}
我在问自己,这个简单的解决方案是否已经奏效,或者我是否忽略了一个重要的方面,因为我在互联网上找到的大多数其他解决方案都很复杂,很难理解。到目前为止我能找到的最好的解决方案使用未绑定的委托。这是某种包装委托,它将事件处理程序和事件订阅者实例作为参数(是的,它要求在委托调用期间传入事件订阅者对象)。
你可以在这里找到这篇很棒的文章:
http://diditwith.net/CommentView,guid,aacdb8ae-7baa-4423-a953-c18c7940ab.aspx#comments启动
"WeakEventManager"类不依赖于知道订阅者类或任何其他信息。除此之外,它还适用于匿名代表。如果解决方案只需要存储对委托的弱引用,那么开发人员为什么要花这么多时间来编写一个不仅有效而且使用方便的解决方案呢?有什么收获?
更新:因为有人否决了这个问题(可能有点不具体),我想给出一个更准确的问题:
这是源代码还是创建一个可工作的弱事件处理程序的首要任务?如果没有,缺少什么?
我是否忽略了的一个重要方面
是的,很重要。你用一个"漏洞"换了另一个。现在,您不再阻止事件订阅者对象被垃圾收集,而是阻止WeakReference对象被收集。你没有领先。
还需要一种机制来清理那些过时的WeakReferences。当它们的IsAlive属性返回false时,您不再需要它们,然后将其从_list
中删除。但您必须单独检查,一些代码需要处理这一点。一个明显的选择是检查何时添加事件或何时触发事件。但这还不够,因为客户端代码只在初始化时添加,并且不能保证事件始终被激发。
因此需要一些类型的方案来稍后执行。任何事情都有可能,但没有什么是非常理想的,因为这是一项繁忙的工作,通常什么都做不成。做出正确的选择很重要。这当然包括而不是这样做,它往往是解决设计问题的创可贴。
WeakEventManager
背后的理念是,它保留了一个对事件目标对象的弱引用列表和一个必须调用的处理程序列表,但不会"将它们联系在一起"(直接订阅事件通常会这样做),允许对目标进行垃圾收集(并定期进行检查,以便在对源进行垃圾收集时相应清空"已订阅"的委托列表)。
这听起来很简单,需要大量的管道代码,而WeakEventManager
所做的就是这些(以易于使用的方式为您进行管道)。
如果你正在将WeakEventManager
克隆到你自己的实现中(或使用内置的),并且它做到了这一点,那么是的,这就是你所需要做的。如果你不是在问这个问题,那么我就不清楚了。
这是源代码还是创建一个可工作的弱事件处理程序的首要任务?如果没有,缺少什么?
这是最重要的一点,Listener
类的其余部分也很重要,更不用说支持这个非委托事件处理程序所需的手动管道了。
例如,检查ListenerList.DeliverEvent
,它比通常的Invoke
调用更复杂一些。
基本上,正常的事件系统假设有强引用,因此为了使用WeakReference
,您最终必须自己添加大量转换逻辑,并决定如何处理由于使用WeakReference
而永远不会触发的事件。