I am doing research on how to properly create a weak referenced event handler. Since WPF has already a solution for avoiding memory leaks with events, I decompiled the "WeakEventManager" class and spent some time on analysing it.
我正在研究如何正确创建弱引用事件处理程序。由于WPF已经有一个避免事件内存泄漏的解决方案,我反编译了“WeakEventManager”类并花了一些时间来分析它。
As I found out, the "WeakEventManager" class relies on creating and storing a weak reference to the target object as well as to the event handler delegate. Here are some code segments:
正如我所发现的,“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);
}
I am asking myself if this simple solution would already be working or did I overlook an important aspect, since most other solutions I found on the Internet are complex and hard to understand. The best solution I could find so far uses an unbound delegate. That is some kind of wrapper delegate that takes the event handler and event subscriber instance as a parameter (yes, it requires the event subscriber object to be passed in during delegate invocation).
我问自己这个简单的解决方案是否已经起作用或者我忽略了一个重要方面,因为我在互联网上发现的大多数其他解决方案都很复杂且难以理解。到目前为止,我能找到的最佳解决方案是使用未绑定的委托。这是某种包装器委托,它将事件处理程序和事件订阅者实例作为参数(是的,它要求在委托调用期间传递事件订阅者对象)。
You can find this great article here:
你可以在这里找到这篇精彩的文章:
http://diditwith.net/CommentView,guid,aacdb8ae-7baa-4423-a953-c18c1c7940ab.aspx#commentstart
The "WeakEventManager" class doesnt't rely on knowing the subscriber class or any additional information. Beyond that it also works with anonymous delegates. Why do developers spent so much time on writing a solution that is not only working but also convenient to use, if a solution only requires them to store a weak reference to the delegate? What's the catch?
“WeakEventManager”类不依赖于知道订阅者类或任何其他信息。除此之外,它还与匿名代表合作。为什么开发人员花了这么多时间编写一个不仅工作而且使用方便的解决方案,如果解决方案只要求他们存储对委托的弱引用?有什么收获?
Update: Because someone downvoted this question (may be it is a little bit unspecific), I want to give a more precise question:
更新:因为有人贬低了这个问题(可能有点不明确),我想提出一个更精确的问题:
Is that source code above all it takes to create a working weak event handler? If not, what is missing?
最重要的是源代码是否需要创建一个有效的弱事件处理程序?如果没有,缺少什么?
3 个解决方案
#1
7
did I overlook an important aspect
我忽略了一个重要方面
Yes, an important one. You traded one "leak" for another. Instead of preventing the event subscriber objects from getting garbage collected, you now prevent WeakReference objects from getting collected. You are not ahead.
是的,一个重要的。你换了另一个“泄漏”。您现在可以防止收集WeakReference对象,而不是阻止事件订阅者对象进行垃圾回收。你没有领先。
What is also required is a mechanism to get those stale WeakReferences cleaned-up. You don't need them anymore when their IsAlive property returns false, you then remove it from _list
. But you have to check that separately, some code needs to take care of that. An obvious choice is to check when an event is added or when it is fired. But that isn't enough, since client code only ever adds at initialization and you can't get a guarantee that the event is consistently fired.
还需要一种机制来清除那些陈旧的WeakReferences。当IsAlive属性返回false时,您不再需要它们,然后将其从_list中删除。但你必须单独检查,一些代码需要处理。一个明显的选择是检查何时添加事件或何时触发事件。但这还不够,因为客户端代码只会在初始化时添加,并且无法保证事件始终被触发。
So some kind of scheme is required to do it later. Anything is possible and nothing is quite ideal because it is a lot of busy-work with often not getting anything done. Making the right choice is important. And that certainly includes not doing this at all, it tends to be a band-aid over a design problem.
因此,稍后需要某种方案。任何事都是可能的,没有什么是非常理想的,因为经常没有完成任何工作需要很多繁忙的工作。做出正确的选择很重要。而这肯定包括不做这件事,它往往是一个设计问题的创可贴。
#2
1
The idea behind the WeakEventManager
is that it keeps a list of weak references to the target object of the events and a list of handlers it must call, but does not "tie them together" (as directly subscribing to events typically does), allowing the target to be garbage collected (and periodically checked so that the "subscribed" delegate list is emptied accordingly when the source is garbage collected).
WeakEventManager背后的想法是它保留一个对事件的目标对象的弱引用列表以及它必须调用的处理程序列表,但不“将它们绑定在一起”(如直接订阅事件通常那样),允许目标是垃圾收集(并定期检查,以便在源被垃圾收集时相应地清空“订阅的”委托列表)。
This, which sounds easy, requires a lot of plumbing code, and that's all the WeakEventManager
does (do the plumbing for you in an easy to use manner).
这听起来很简单,需要大量的管道代码,这就是WeakEventManager所做的一切(以易于使用的方式为您做管道工作)。
If you are cloning out WeakEventManager
to your own implementation (or using the built-in) and it does that, then yes, that's all you need to do. If that's not what you are asking, then the question is unclear to me.
如果你将WeakEventManager克隆到你自己的实现(或者使用内置的)并且它会这样做,那么是的,这就是你需要做的全部。如果这不是你问的问题,那么这个问题我不清楚。
#3
0
Is that source code above all it takes to create a working weak event handler? If not, what is missing?
最重要的是源代码是否需要创建一个有效的弱事件处理程序?如果没有,缺少什么?
That is the most important bit, the rest of the Listener
class is important as well, not to mention the manual plumbing required to support this non-delegate event handler.
这是最重要的一点,Listener类的其余部分也很重要,更不用说支持这个非委托事件处理程序所需的手动管道。
For instance check out ListenerList.DeliverEvent
which is a bit more involved than the usual Invoke
call.
例如,检查一下ListenerList.DeliverEvent,它比通常的Invoke调用更复杂一些。
Basically the normal event system assumes strong references so in order to use WeakReference
you end up having to add a lot of the translation logic yourself as well as deciding how to handle events that never fire due to using WeakReference
.
基本上,普通事件系统假定强引用,因此为了使用WeakReference,您最终必须自己添加大量翻译逻辑,以及决定如何处理因使用WeakReference而从未触发的事件。
#1
7
did I overlook an important aspect
我忽略了一个重要方面
Yes, an important one. You traded one "leak" for another. Instead of preventing the event subscriber objects from getting garbage collected, you now prevent WeakReference objects from getting collected. You are not ahead.
是的,一个重要的。你换了另一个“泄漏”。您现在可以防止收集WeakReference对象,而不是阻止事件订阅者对象进行垃圾回收。你没有领先。
What is also required is a mechanism to get those stale WeakReferences cleaned-up. You don't need them anymore when their IsAlive property returns false, you then remove it from _list
. But you have to check that separately, some code needs to take care of that. An obvious choice is to check when an event is added or when it is fired. But that isn't enough, since client code only ever adds at initialization and you can't get a guarantee that the event is consistently fired.
还需要一种机制来清除那些陈旧的WeakReferences。当IsAlive属性返回false时,您不再需要它们,然后将其从_list中删除。但你必须单独检查,一些代码需要处理。一个明显的选择是检查何时添加事件或何时触发事件。但这还不够,因为客户端代码只会在初始化时添加,并且无法保证事件始终被触发。
So some kind of scheme is required to do it later. Anything is possible and nothing is quite ideal because it is a lot of busy-work with often not getting anything done. Making the right choice is important. And that certainly includes not doing this at all, it tends to be a band-aid over a design problem.
因此,稍后需要某种方案。任何事都是可能的,没有什么是非常理想的,因为经常没有完成任何工作需要很多繁忙的工作。做出正确的选择很重要。而这肯定包括不做这件事,它往往是一个设计问题的创可贴。
#2
1
The idea behind the WeakEventManager
is that it keeps a list of weak references to the target object of the events and a list of handlers it must call, but does not "tie them together" (as directly subscribing to events typically does), allowing the target to be garbage collected (and periodically checked so that the "subscribed" delegate list is emptied accordingly when the source is garbage collected).
WeakEventManager背后的想法是它保留一个对事件的目标对象的弱引用列表以及它必须调用的处理程序列表,但不“将它们绑定在一起”(如直接订阅事件通常那样),允许目标是垃圾收集(并定期检查,以便在源被垃圾收集时相应地清空“订阅的”委托列表)。
This, which sounds easy, requires a lot of plumbing code, and that's all the WeakEventManager
does (do the plumbing for you in an easy to use manner).
这听起来很简单,需要大量的管道代码,这就是WeakEventManager所做的一切(以易于使用的方式为您做管道工作)。
If you are cloning out WeakEventManager
to your own implementation (or using the built-in) and it does that, then yes, that's all you need to do. If that's not what you are asking, then the question is unclear to me.
如果你将WeakEventManager克隆到你自己的实现(或者使用内置的)并且它会这样做,那么是的,这就是你需要做的全部。如果这不是你问的问题,那么这个问题我不清楚。
#3
0
Is that source code above all it takes to create a working weak event handler? If not, what is missing?
最重要的是源代码是否需要创建一个有效的弱事件处理程序?如果没有,缺少什么?
That is the most important bit, the rest of the Listener
class is important as well, not to mention the manual plumbing required to support this non-delegate event handler.
这是最重要的一点,Listener类的其余部分也很重要,更不用说支持这个非委托事件处理程序所需的手动管道。
For instance check out ListenerList.DeliverEvent
which is a bit more involved than the usual Invoke
call.
例如,检查一下ListenerList.DeliverEvent,它比通常的Invoke调用更复杂一些。
Basically the normal event system assumes strong references so in order to use WeakReference
you end up having to add a lot of the translation logic yourself as well as deciding how to handle events that never fire due to using WeakReference
.
基本上,普通事件系统假定强引用,因此为了使用WeakReference,您最终必须自己添加大量翻译逻辑,以及决定如何处理因使用WeakReference而从未触发的事件。