2009-07-15 5 views
3

Ich habe festgestellt, interessantes Verhalten in unserer .NET WinForms App. Wir haben eine MDI-Form, die viele MDI-Kinder hinzugefügt hat. Diese untergeordneten Formen hören auf ein "Broadcast" -Ereignis, das im Wesentlichen eine Aufforderung zur Aktualisierung ist. Das Ereignis wird in einer Basisklasse deklariert, und die Listenereignisse werden in den untergeordneten Formularen hinzugefügt.Interessantes Ereignis "Dispose" Verhalten

Ich habe festgestellt, dass selbst wenn diese untergeordneten Formulare geschlossen sind, die Ereignisse immer noch getroffen werden, wenn das Ereignis nicht explizit in der Dispose() -Methode entfernt wird.

Was ist der Grund dafür? Sicher, wenn das Formular geschlossen ist, sollten die Ereignisse getrennt/entsorgt werden? Liegt es daran, dass das eigentliche Ereignis selbst in einer externen Klasse deklariert ist? Das nehme ich an.

Insight würde sehr geschätzt werden.

(mit C#, .NET 3.5)

Antwort

4

Der Veranstaltung, die noch im Rahmen, da es auf der Hauptform ist, hat noch einen Verweis auf die Delegierten in dem untergeordneten Fenster. Daher wird das Schließen des Fensters das Objekt nicht beseitigen, da es auch durch diese Referenz noch im Geltungsbereich ist. Dies ist ein sehr gängiger Weg, um in .NET ein "Speicherleck" zu bekommen. Bedenken Sie auch, dass das untergeordnete Fenster immer noch im Geltungsbereich ist und dass alles innerhalb des Fensters noch im Geltungsbereich ist und auch nicht erfasst wird.

Warum das Fenster nicht alle Ereignishandler beim Schließen trennen. Es wäre sehr merkwürdig, wenn es so wäre. Nur weil Sie ein Fenster geschlossen haben, bedeutet das nicht, dass Sie damit fertig sind. Sie könnten es wieder öffnen und Daten speichern, um den Status beizubehalten. Das Schließen auf ein Fenster hat keine besonderen Eigenschaften gegenüber dem Aufruf einer anderen Methode, es verfügt nicht über das Fenster, markiert es für die Sammlung oder irgendetwas anderes.

1

Sie haben Recht. Wenn Sie ein Ereignis registrieren, wird dem Ereignisdelegaten (in dem Objekt, dem dieses Ereignis gehört) ein Verweis auf Ihr Formular hinzugefügt. Wenn Sie die Registrierung nicht entfernen, wird in Ihrem Formular keine Garbage Collections gesammelt, da immer noch mindestens ein Verweis darauf (der Delegat) vorhanden ist und die Aufrufe immer noch ausgegeben werden, wenn das Ereignis ausgelöst wird.

Sie sollten immer sicherstellen, dass Ereignisse abbestellt werden, um diese Art von Leckagen zu vermeiden.

1

Ja, dies ist das Verhalten von Design, das ist auch der Grund, warum die WeakEvent Muster wurde konzipiert.

0

Ihr Ereignisabonnement zählt als Verweis auf Ihr untergeordnetes Formular. (Ihre Kinder werden also auch nicht mit Müll entsorgt).

Um zu sehen, was vor sich geht, suchen Sie die Hilfe zu einem Delegaten auf. Es hat ein Mitglied namens Target (vom Typ Objekt), das auf den Abonnenten zeigt. Also, Sie haben immer noch eine Referenzkette am Leben:

MDI Parent (Event-Publisher) - > der Delegierte - > Ihr Kind Form.

Sie müssen Ihre Ereignisabonnements in Dispose() bereinigen, oder Ihre untergeordneten Formulare sind nie für die Garbage Collection geeignet.

Nun, wenn Sie sich im Internet nach "schwachen ref-Ereignissen" umsehen, finden Sie eine Reihe von Problemumgehungen, die Leute zur Definition schwacher Ereignisse gepostet haben. Hier ist nur ein Beispiel: http://www.codeproject.com/KB/cs/weakeventhandlerfactory.aspx

Ich musste einen Prototyp auch, und ich würde mich freuen, es zu teilen, wenn Sie es wollen. Mein Rat wäre jedoch, bei regelmäßigen Ereignissen zu bleiben und in Dispose() aufzuräumen.