2010-07-02 2 views
1

J'ai une méthode qui, tout au long de la vie de mon application, est ajouté à un certain nombre d'événements. À un moment donné, j'aimerais supprimer la méthode de tous les événements qui la référencent. Je ne connais que la méthode ... J'aimerais ne pas garder un List<EventHandler> local de tous les événements auxquels la méthode est ajoutée parce que je pense que quelque part/en quelque sorte le CLR fait cela pour moi dans le but de la collecte des ordures. Du pseudo-code ci-dessous, des idées? Merci ...C# - avoir méthode, besoin de supprimer ou de découvrir tous les événements qui le référencent

Ce que je veux faire:

public class Subscriber 
{ 
    public virtual void EventRaised(object pSender, EventArgs pArguments) 
    { 
    MessageBox.Show("EventRaised"); 
    } 

    public virtual void UnsubscribeAll() 
    { 
    //Something like: 
    EventRaised.RemoveReferences(); 
    //or 
    foreach(var MyReference in EventRaised.References) 
     MyReference.Remove(); 
    } 
} 

var MySubscriber = new Subscriber(); 

ThisEvent += MySubscriber.EventRaised; 
ThatEvent += MySubscriber.EventRaised; 
//on and on... 

MySubscriber.UnsubscribeAll(); 

Ce que je ne veux pas faire:

public class Subscriber 
{ 
    protected List<EventHandler> Publishers = new List<EventHandler>(); 

    public virtual void EventRaised(object pSender, EventArgs pArguments) 
    { 
    MessageBox.Show("EventRaised"); 
    } 

    public virtual void Subscribe(EventHandler pPublisher) 
    { 
    pPublisher += EventRaised; 
    Publishers.Add(pPublisher); 
    } 

    public virtual void UnsubscribeAll() 
    { 
    foreach(var Publisher in Publishers) 
     Publisher -= EventRaised; 

    Publishers.Clear(); 
    } 
} 

var MySubscriber = new Subscriber(); 

MySubscriber.Subscribe(ThisEvent); 
MySubscriber.Subscribe(ThatEvent); 
//on and on... 

MySubscriber.UnsubscribeAll(); 

Un autre exemple

Si le CLR ne tient pas compte des références par Stephen Cleary - Bummer ... qui me force à me projeter B. Les réponses et commentaires ne correspondent pas vraiment à mon problème - c'est de ma faute si je vais ajouter un autre exemple ci-dessous. L'exemple de code # 1 de JBall est très intéressant et je vais ajouter ça à mon sac de trucs.

Je ne supprime pas les références d'événement à la méthode avec la nécessité ou l'intention de les restaurer plus tard ... Je veux juste qu'elles soient parties. Que diriez-vous de ce pseudo-code - du point de vue de l'Enfant, je veux dire "oubliez tous les événements auxquels mon Parent a attaché et attachés à ces événements à la place." J'ai plusieurs solutions de contournement, y compris en gardant un List<> des événements attachés, mais j'espérais tirer parti du travail que le CLR fait pour moi dans les coulisses. Un avantage supplémentaire d'une structure CLR-maintenue aurait été le fait qu'il est définitif et final ... il n'y aurait eu aucune chance d'attacher une méthode à un événement sans réellement enregistrer la référence.

public class Parent 
{ 
    public Parent() 
    { 
    AnObject.ThisEvent += EventRaised; 
    AnObject.ThatEvent += EventRaised; 
    } 

    public virtual void EventRaised(object pSender, EventArgs pArguments) 
    { 
    MessageBox.Show("EventRaised"); 
    } 
} 

public class Child 
{ 
    public Child(): base() 
    { 
    //What I want to do: 
    EventRaised.RemoveAllEventReferences(); 

    AnotherObject.ThisEvent += EventRaised; 
    AnotherObject.ThatEvent += EventRaised; 
    } 
} 
+0

L'enfant hérite de Parent? – jball

Répondre

1

Demandez à votre appel de méthode EventRaised un autre délégué qui vous par assign par défaut, et quand UnsubscribeAll() est appelé, supprimer cet événement de votre délégué intérieur.

public class Subscriber 
{ 
    EventHander m_InnerEvent; 

    public Subscriber() 
    { 
     m_InnerEvent += InnerEventRaised; 
    } 

    public virtual void EventRaised(object pSender, EventArgs pArguments) 
    { 
     m_InnerEvent(pSender, pArguments); 
    } 

    protected virtual void InnerEventRaised(object pSender, EventArgs pArguments) 
    { 
     Console.WriteLine("EventRaised"); 
    } 

    public virtual void UnsubscribeAll() 
    { 
     m_InnerEvent -= InnerEventRaised; 
    } 
} 

Alternativement, un drapeau qui se prépare quand UnsubscribeAll() est appelé, et vérifier que le drapeau de votre méthode EventRaised. Pour votre nouvel exemple, si c'est en fait la structure de ce que vous essayez de faire, vous devez simplement refactoriser. Tout se passe dans les constructeurs et le constructeur Child est simplement en train de défaire ce qui a été fait dans le constructeur Parent. Déplace les bits des actions du constructeur Parent dans une méthode. L'enfant peut alors ignorer cette méthode pour ignorer ce que Parent ferait et faire ce qu'il veut à la place:

public class Parent 
{ 
    public Parent() 
    { 
     AttachEventsToThings(); 
    } 

    protected virtual void AttachEventsToThings() 
    { 
     AnObject.ThisEvent += EventRaised; 
     AnObject.ThatEvent += EventRaised; 
    } 

    public virtual void EventRaised(object pSender, EventArgs pArguments) 
    { 
     MessageBox.Show("EventRaised"); 
    } 
} 

public class Child : Parent 
{ 
    protected override void AttachEventsToThings() 
    { 
     AnotherObject.ThisEvent += EventRaised; 
     AnotherObject.ThatEvent += EventRaised; 
    } 
} 
+3

Pour clarifier, c'est la seule façon de le faire. Le CLR ne conserve pas de liste comme vous le suspectez; le GC fonctionne via un algorithme "mark and sweep". –

+0

Si vous devez autoriser la réabonnement après 'UnsubscribeAll', vous pouvez utiliser la classe' CallbackContext' de [Nito.Async] (http://nitoasync.codeplex.com/). J'ai [un article de blog] (http://nitoprograms.blogspot.com/2009/04/asynchronous-callback-contexts.html) qui va plus en détail sur le concept. –

+0

@Stephen: Si c'est la bonne réponse, pourquoi ne l'avez-vous pas upvote? En outre, votre commentaire a reçu deux upvotes, ce qui signifie que cette réponse devrait déjà avoir trois upvotes? –

Questions connexes