IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

s'abonner à un event empeche t'il la destruction?


Sujet :

C#

  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Points : 488
    Points
    488
    Par défaut s'abonner à un event empeche t'il la destruction?
    Bonjour
    tentant de débuger une fuite mémoire dans mon logiciel, je crois que je suis en train de découvrir une chose qui me térrifie (car je ne l'ai absolument pas gérée).

    J'ai l'impression que si mon objet s'abonne à l'event de quelque chose de persistant. Alors mon objet ne sera jamais détruit.

    exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    public class MaClasse1()
    {
       public MaClasse1(IContent obj)
       {
             obj.UnEvent +=new EventHandler(Test);
       }
     
       private void Test(object sender,EventArg e)
      {
         //blablabla
      }
     
    }
     
    public class Program
    {
        public static void Main()
       {
           IContent content = new Content();
           MaClasse1 obj = new MaClasse1(content);
           obj = null; // Bien que obj etait l'unique référent l'instance n'est pas détruite.
           //Plein de choses se passent, pour moi l'instance de MaClasse1 n'est plus, et pourtant : 
          content.DeclencheEvent(); //Fait que l'ex obj recoit l'event alors qu'il est cencé etre détruit ...
     
       }
    }
    Pourriez vous confirmer cette théorie?

    Merci

  2. #2
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Points : 488
    Points
    488
    Par défaut
    Arg ! le couperet vient de tomber, j'ai trouvé la réponse sur un autre site :

    publisher.SomeEvent += target.DoSomething;

    then publisher has a reference to target but not the other way round.
    [...]
    The tricky case is when the publisher is long-lived but the subscribers don't want to be - in that case you need to unsubscribe the handlers.
    la réponse est donc oui, ca empêche la destruction car celui qui publie l'événement garde du coup une référence vers l'abonné

    C'est vrai que ca parrait logique apres tout.

    Du coup je trouve que Visual Studio nous pousse vers un TRES mauvais reflexe :
    Lorsque l'on s'abonne à un événement, Visual nous propose de créer la callback pour nous : "Press Tab to generate new EventHandler..."

    C'est très mauvais car on n'a pas la main pour nous désabonner par la suite. Il aurait été préférable qu'il crée dans la classe, une variable EventHandler que l'on pourrait par la suite utiliser pour se désabonner. Même ajouter dans la Méthode Dispose un désabonnement n'aurait pas été un luxe !

    Bon et bien je vais en avoir pour des jours à décrasser mon code

  3. #3
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Février 2003
    Messages
    2 182
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2003
    Messages : 2 182
    Points : 4 496
    Points
    4 496
    Par défaut
    Tu peux faire une recherche sur "memory leak with event" dans google, j'ai vu aussi il y a un petit temps post sur le sujet si tu es réellement interresé par la problématique

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2009
    Messages
    2 032
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2009
    Messages : 2 032
    Points : 5 476
    Points
    5 476
    Par défaut
    Le "Tab" c'est fait pour aller plus vite. Maintenant il est toujours possible de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    toto.click += new eventhandler(xxxx) // Abonnement
    toto.click -= new eventhandler(xxxx) //Desabonnement
    Tu peux par exemple implémenter l'interface IDisposable et dans le Dispose mettre tout les désabonnements.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static void Main()
       {
           IContent content = new Content();
           MaClasse1 obj = new MaClasse1(content);
    obj.Dispose();
           obj = null; // Bien que obj etait l'unique référent l'instance n'est pas détruite.
           //Plein de choses se passent, pour moi l'instance de MaClasse1 n'est plus, et pourtant : 
          content.DeclencheEvent(); //Fait que l'ex obj recoit l'event alors qu'il est cencé etre détruit ...
     
       }

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Points : 488
    Points
    488
    Par défaut
    toto.click -= new eventhandler(xxxx) //Desabonnement
    es tu sur de ca?
    parceque qui dit new, dit une nouvelle instance d'objet. Je serai donc étonné que ca désabonne...

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par giova_fr Voir le message
    Du coup je trouve que Visual Studio nous pousse vers un TRES mauvais reflexe :
    Lorsque l'on s'abonne à un événement, Visual nous propose de créer la callback pour nous : "Press Tab to generate new EventHandler..."

    C'est très mauvais car on n'a pas la main pour nous désabonner par la suite. Il aurait été préférable qu'il crée dans la classe, une variable EventHandler que l'on pourrait par la suite utiliser pour se désabonner. Même ajouter dans la Méthode Dispose un désabonnement n'aurait pas été un luxe !
    C'est pas un problème en fait... quand tu fais ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    publisher.SomeEvent += target.DoSomething;
    C'est en fait un raccourci pour
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    publisher.SomeEvent += new EventHandler(target.DoSomething);
    (conversion implicite de groupe de méthode en délégué)

    Et si tu fais ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    publisher.SomeEvent -= new EventHandler(target.DoSomething);
    Tu utilises effectivement une nouvelle instance de EventHandler pour te désabonner, mais comme elle est "égale" (même cible et même méthode) à celle que tu as utilisé pour l'abonnement, ça fonctionne quand même

  7. #7
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Points : 488
    Points
    488
    Par défaut
    ok merci pour cet éclairsissement.

    C'est génial, mais il y a quand meme une chose que je ne comprend pas trop.
    ok la cible est la même.

    Mais il y a quand même un objet qui contient cette cible (un Delegate?)
    comment un "new" peut il retourner une référence unique?

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par giova_fr Voir le message
    comment un "new" peut il retourner une référence unique?
    Il ne retourne pas une référence unique, mais deux instances peuvent être considérées comme identiques (en redéfinissant la méthode Equals). C'est le même principe que quand tu retires un objet d'une liste : ça retire le premier objet qui est considéré comme égal à l'objet spécifié.

    Soit dit en passant, il y a au moins un cas où l'opérateur new renvoie une instance existante au lieu d'en créer une nouvelle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        string s1 = new string('x', 0);
        string s2 = new string('x', 0);
        bool sameInstance = ReferenceEquals(s1, s2); // true
    Mais c'est juste une optimisation du CLR pour ne pas multiplier les instances de chaine vide...

  9. #9
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Points : 488
    Points
    488
    Par défaut
    Je ressort grandi de cette discution encore merci !

    PS : la boutique de free mobile toujours fermée, 4 ans que je l'attends, je n'en peux plus !

  10. #10
    Membre éclairé
    Homme Profil pro
    Développeur / architecte
    Inscrit en
    Juillet 2009
    Messages
    473
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur / architecte

    Informations forums :
    Inscription : Juillet 2009
    Messages : 473
    Points : 674
    Points
    674
    Par défaut
    Si c'est en WPF, il y a moyen d'utiliser le weak event pattern
    Si c'est du Silverlight, tu trouveras des implémentations du pattern sur le web.

    A+

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Abonnement à un event non disponible
    Par Jamming Ed dans le forum C#
    Réponses: 3
    Dernier message: 17/06/2011, 17h52
  2. empecher les doubles abonnements aux events
    Par giova_fr dans le forum Windows Forms
    Réponses: 1
    Dernier message: 16/07/2009, 03h30
  3. abonnement à un event qui disparaît
    Par joujoukinder dans le forum C#
    Réponses: 3
    Dernier message: 07/05/2009, 18h17
  4. Réponses: 6
    Dernier message: 22/08/2007, 14h45
  5. Réponses: 4
    Dernier message: 26/06/2007, 15h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo