62 votes

Avez-vous besoin de supprimer un gestionnaire d'événements dans le destructeur?

J'utilise de la UserControls qui sont créés et détruits dans mon application en cours d'exécution (par la création et fermeture de plusieurs fenêtres avec ces contrôles à l'intérieur).
C'est un WPF UserControl et hérite System.Windows.Controls.UserControl. Il n'y a pas d' Dispose() méthode je pourrais le remplacer.
PPMM est Singleton avec la même durée de vie que mon application.
Maintenant, dans le constructeur de ma (WPF) UserControl,- je ajouter un gestionnaire d'événements:

    public MyControl()
    {
        InitializeComponent();

        // hook up to an event
        PPMM.FactorChanged += new ppmmEventHandler(PPMM_FactorChanged);
    }

Je me suis habitué à la suppression de ce gestionnaire d'événement dans le destructeur:

    ~MyControl()
    {
        // hook off of the event
        PPMM.FactorChanged -= new ppmmEventHandler(PPMM_FactorChanged);
    }

Aujourd'hui, je suis tombé sur ce et a demandé:

1) Est-ce nécessaire? Ou ne le GC prendre soin d'elle?

2) est-ce même travail? Ou aurais-je stocker le nouveau ppmmEventHandler?

Je suis impatient de vos réponses.

39voto

Lasse V. Karlsen Points 148037

Depuis PPMM est une longue durée de vie de l'objet (singleton), ce code n'a pas beaucoup de sens.

Le problème ici est que tant que le gestionnaire d'événements est en faisant référence à l'objet, elle ne sera pas éligible pour la collecte des ordures, du moins aussi longue que celle d'un autre objet qui est propriétaire de l'événement est vivant.

En tant que tel, de mettre n'importe quoi dans le destructeur est inutile, soit:

  1. Le gestionnaire d'événement a déjà été supprimé, ainsi que l'objet est devenu admissible pour la collecte des ordures
  2. Le gestionnaire d'événement n'est pas supprimé, c'est le propriétaire de l'objet n'est pas admissible pour la collecte des ordures, et donc le finaliseur ne sera jamais appelé
  3. Les deux objets sont admissibles pour la collecte des ordures, dans ce cas, vous ne devez pas accéder à cet autre objet, dans le finaliseur puisque vous ne connaissez pas son état interne

En bref, ne faites pas cela.

Maintenant, un autre argument peut être dit à propos de l'ajout d'un tel code de l' Dispose méthode, lorsque vous êtes à la mise en œuvre de IDisposable. Dans cette affaire, il rend parfaitement logique, puisque son code d'utilisateur appelant Dispose, à une prédéfinis et point contrôlé.

Le finaliseur (destructeur), cependant, est seulement appelée lorsque l'objet est admissible pour la collecte des ordures et a un finaliseur, auquel cas il n'y a pas de point.

Comme pour la question nbr. 2, que je prends comme "puis-je me désabonner à partir d'événements comme ça", alors oui, vous le pouvez. Le seul moment où vous en avez besoin pour tenir à l'délégué que vous avez utilisé pour vous inscrire avec, c'est quand vous êtes à la construction de la délégué autour d'une méthode anonyme ou d'une expression lambda. Lorsque vous êtes à la construction autour d'une méthode existante, il va fonctionner.


Edit: WPF. droit, de ne pas voir que la balise. Désolé, le reste de ma réponse n'a pas beaucoup de sens pour WPF et depuis je ne suis WPF-gourou, je ne peux pas vraiment dire. Cependant, il y a un moyen de résoudre ce problème. Il est tout à fait légal ici sur AFIN de récupérer le contenu d'une autre réponse si vous pouvez l'améliorer. Donc si quelqu'un sait comment faire cela avec un WPF usercontrol, vous êtes libre de soulever l'ensemble de la première partie de ma réponse et ajoutez le bits de WPF.

Edit: Permettez-moi de répondre à la question dans le commentaire à l'intérieur ici.

Depuis la classe en question est un contrôle utilisateur, sa durée de vie sera liée à un formulaire. Lorsque le formulaire est en cours de fermeture, il va disposer de tous les contrôles enfants qu'il possède, en d'autres termes, il existe déjà une méthode dispose ici présents.

La façon correcte pour un contrôle à l'utilisateur de gérer la situation, si elle gère ses propres activités, est de décrocher les gestionnaires d'événements dans la méthode dispose.

(reste supprimé)

9voto

Tigran Points 41381

Premièrement, je dirais qu’il ne faut pas utiliser un destructeur mais Dispose () pour effacer vos ressources.

En second lieu , par mon avis, si ce code est à l' intérieur d' un objet qui a créé très souvent et ont courte durée de vie, il est préférable que vous prenez soin de retirer gestionnaire d'événements comme ceci est un lien vers objet porteur, ce qui empêchera GC pour les recueillir.

Cordialement.

8voto

Paul Groke Points 2799

WPF ne prend pas en charge IDisposable bien. Si vous êtes à la mise en œuvre d'un contrôle WPF qui a besoin de nettoyage, vous devriez penser à d'accrochage dans l' Loaded et Unloaded des événements au lieu (ou en plus).

I. e. vous vous connectez à l'événement dans l' Loaded gestionnaire et les débrancher dans l' Unloaded gestionnaire. Bien sûr, ce n'est qu'une option si votre contrôle n'a pas besoin de recevoir de l'événement alors qu'il n'est pas "chargé" et si vous le pouvez correctement en charge de nombreux cycles de chargement/déchargement.

L'avantage de l'utilisation de l' Loaded/Unloaded événements, c'est que vous n'avez pas manuellement éliminer l'utilisateur de contrôler partout où il est utilisé. Vous devez cependant être conscient que l' Unloaded événement n'est pas déclenché après l'arrêt de l'application a commencé. E. g. si votre mode d'arrêt est - OnMainWindowClose, l' Unloaded événements pour les autres windows ne sera pas déclenché. Ce n'est généralement pas un problème. Il signifie simplement que vous ne pouvez pas faire des trucs de manière fiable dans un Unloaded qui doivent se produire avant/pendant que l'application se termine.

2voto

Yochai Timmer Points 19802

Si le code parvient au destructeur, cela n'a plus d'importance.

C'est parce qu'il ne sera détruit que s'il n'écoute plus aucun événement.
S'il écoutait toujours les événements, il n'aurait pas été détruit.

2voto

Damien_The_Unbeliever Points 102139

Est-ce que PPMM externe avec une durée de vie plus longue que les instances MyControl ?

Si tel est le cas, à moins que PPMM_FactorChanged soit une méthode statique, le ppmmEventHandler conservera une référence à l'instance MyControl direct - ce qui signifie que l'instance ne sera jamais éligible pour la collecte des ordures, et le finaliseur ne sera jamais déclenché.

Vous ne devriez pas avoir besoin de garder le ppmmEventHandler pour le code de suppression.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X