2009-07-15 6 views
3

J'ai remarqué un comportement intéressant dans notre application .NET WinForms. Nous avons une forme mdi qui a de nombreux enfants mdi ajoutés. Ces formes enfant écoutent un événement "broadcast" qui est essentiellement un appel à se rafraîchir. L'événement est déclaré dans une classe de base et les événements d'écoute sont ajoutés dans les formulaires enfants.Intéressant comportement "Dispose"

J'ai remarqué que même lorsque ces formulaires enfants sont fermés, les événements sont toujours en cours, si l'événement n'est pas explicitement supprimé dans la méthode Dispose().

Quel est le raisonnement derrière cela? Sûrement si le formulaire est fermé, les événements devraient être détachés/éliminés? Est-ce parce que l'événement lui-même est déclaré dans une classe extérieure? C'est ce que je présume.

Un aperçu serait très apprécié.

(en utilisant C#, .NET 3.5)

Répondre

4

L'événement, qui est toujours portée puisqu'il est sur la principale forme, a encore une référence au délégué dans la fenêtre de l'enfant. Par conséquent, la fermeture de la fenêtre ne disposera pas de l'objet, car il est toujours dans la portée de cette référence. C'est une façon très courante d'obtenir une "fuite de mémoire" dans .NET. Tenez également compte du fait que la fenêtre enfant étant toujours visible, tout ce qui est à l'intérieur de la fenêtre est toujours visible et ne sera pas collecté.

En ce qui concerne les raisons pour lesquelles la fenêtre ne détache pas tous les gestionnaires d'événements à proximité. Ce serait un comportement très étrange si c'était le cas. Juste parce que vous avez fermé une fenêtre ne signifie pas que vous en avez fini avec elle, vous pourriez le rouvrir, enregistrer des données à partir de l'état persistant. Appeler à proximité d'une fenêtre n'a pas de propriétés spéciales sur l'appel d'une autre méthode, elle ne dispose pas de la fenêtre, la marque pour la collection ou toute autre chose.

1

Vous avez raison. Lorsque vous enregistrez un événement, une référence à votre formulaire est ajoutée au délégué d'événement (dans l'objet qui possède cet événement). Sauf si vous supprimez l'enregistrement, votre formulaire ne sera jamais récupéré car il y a toujours au moins une référence à celui-ci (le délégué), et les appels seront toujours émis lorsque l'événement est déclenché.

Vous devez toujours vous assurer que les événements sont désinscrits, afin d'éviter ce type de fuite.

1

Oui, c'est le comportement par conception, qui est également la raison pour laquelle le modèle WeakEvent a été conçu.

0

Votre abonnement à un événement "compte" comme référence à votre formulaire enfant. (Ainsi, vos formulaires pour enfants ne sont pas collectés par les ordures non plus).

Pour voir ce qui se passe, recherchez l'aide sur un délégué. il a un membre appelé Target (de type object) qui pointe vers l'abonné. Donc, vous avez toujours une chaîne de référence en vie:

MDI Parent (éditeur d'événements) - > le délégué - > votre formulaire enfant.

Vous devez nettoyer vos abonnements à des événements dans Dispose(), sinon vos formulaires enfants ne seront jamais éligibles pour la collecte des ordures. Maintenant, si vous recherchez sur le web des "événements de faible affaiblissement", vous trouverez un certain nombre de solutions de contournement que les utilisateurs ont publiées pour définir des événements faibles. Voici un exemple: http://www.codeproject.com/KB/cs/weakeventhandlerfactory.aspx

J'ai aussi dû en faire un prototype, et je serais heureux de le partager si vous le souhaitez. Cependant, mon conseil serait de coller avec les événements réguliers et nettoyer dans Dispose().

Questions connexes