Interesting event “Dispose” behaviour

百般思念 提交于 2019-12-21 20:10:06

问题


I have noticed interesting behaviour in our .NET WinForms app. We have an mdi form that has many mdi children added. These child forms listen to a "broadcast" event which is in essence a call to refresh itsself. The event is declared in a base class and the listening events added in the child forms.

I've noticed that even when these child forms are closed, the events are still being hit, if the event is not explicitly removed in the Dispose() method.

What is the reasoning behind this? Surely if the form is closed, the events should be detached/disposed of? Is it because the actual event itself is declared in an outside class? This is what I am presuming.

Insight would be much appreciated.

(using C#, .NET 3.5)


回答1:


The event, which is still in scope since it is on the main form, still has a reference to the delegate in the child window. Therefore closing the window will not dispose of the object because it too is still in scope through this reference. This is a very common way the get a "memory leak" in .NET. Also consider that because the child window is still in scope everything inside the window is still in scope and also won't get collected.

As for why the window doesn't detach all event handlers on close. It would be very strange behaviour if it did. Just because you have closed a window doesn't mean you are finished with it, you could reopen it, save data from it to persist state. Calling close on a window has no special properties over calling any other method, it doesn't dispose of the window, mark it for collection or anything else.




回答2:


You are correct. When you register an event, a reference to your form is added to the event delegate (in the object that owns that event). Unless you remove the registration, your form will never get garbage collected because it there is still at least one reference to it (the delegate), and the calls with still be issued when the event is raised.

You should always ensure events get unsubscribed, to avoid this kind of leakage.




回答3:


Yes, this is the behaviour by design, which is also the reason why the WeakEvent pattern was concieved.




回答4:


Your event subscription "counts" as a reference to your child form. (so your child forms are not being garbage collected either).

To see what's going on, look up the help on a delegate. it has a member called Target (of type object) that points to the subscriber. So, you still have a reference chain alive:

MDI Parent (event publisher) --> the delegate --> your child form.

You have to clean up your event subscriptions in Dispose() or your child forms will never be eligible for garbage collection.

Now, if you look around on the web for "weak ref events", you will find a number of workarounds that people have posted for defining weak events. Here's just one example: http://www.codeproject.com/KB/cs/weakeventhandlerfactory.aspx

I have had to prototype one as well, and I would be happy to share it if you want it. However, my advice would be to stick with regular events and clean up in Dispose().



来源:https://stackoverflow.com/questions/1131414/interesting-event-dispose-behaviour

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!