2009-05-03 13 views
17

Comment voulez-vous suggérer la meilleure façon d'éviter les abonnements aux événements en double? Si cette ligne de code s'exécute à deux endroits, l'événement sera exécuté deux fois. J'essaie d'éviter que les événements de tiers ne s'abonnent deux fois.double abonnements d'événements en C#

theOBject.TheEvent += RunMyCode; 

Dans mon setter délégué, je peux courir efficacement cette ...

theOBject.TheEvent -= RunMyCode; 
theOBject.TheEvent += RunMyCode; 

mais est-ce la meilleure façon?

Répondre

19

Je pense, la façon la plus efficace, est de faire de votre événement une propriété et ajouter des verrous d'accès concurrentiel à lui comme dans ce Example:

private EventHandler _theEvent; 
private object _eventLock = new object(); 
public event EventHandler TheEvent 
{ 
    add 
    { 
     lock (_eventLock) 
     { 
      _theEvent -= value; 
      _theEvent += value; 
     } 
    } 
    remove 
    { 
     lock (_eventLock) 
     { 
      _theEvent -= value; 
     } 
    } 
} 
+2

Dave Morton a changé de nom de domaine. La nouvelle URL est: http://codinglight.blogspot.com/2009/02/preventing-duplicate-subscriptions-to.html –

+0

Pour votre information, si vous obtenez un 503 au lien juste rafraîchir la page. Il a semblé charger après quelques tentatives pour moi. – Dan

1

Si vous possédez la source de la classe de theObject, vous avez accès à la liste InvocationList de TheEvent. Vous pouvez implémenter votre propre accesseur pour l'événement et vérifier avant d'ajouter.

Cependant, je pense que votre approche est très bien aussi.

2

est votre multifil de code? Le verrouillage simultané est nécessaire uniquement lorsqu'il est multi-threadé. Si ce n'est pas un frais généraux.

En tant que tel votre approche de désinscription et d'abonnement est correcte.

Merci

0

-je utiliser votre approche, sauf un détail. Je pense que les événements doivent être souscrits lorsque vous créez une nouvelle instance d'abonné ou de l'objet, ce qui rend le code plus direct. Ainsi, tout ce dont vous avez besoin est juste de regarder attentivement après la disposition des objets corrects (disposer de patten est une solution pratique pour cela).

Vous avez mentionné que vous utilisez un événement tiers, ce qui signifie que vous ne pouvez pas fournir votre propre réalisation pour les méthodes d'ajout/suppression, comme cela vous a été conseillé. Mais dans vos propres classes avec vos propres événements, vous devez définir votre propre réalisation des méthodes d'ajout/suppression d'événement afin de résoudre votre problème.

4

Je l'ai fait avant .... il suppose qu'il est acceptable que le dernier abonné est ce qui est appelé.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyObject my = new MyObject(); 
      my.Changed += new EventHandler(my_Changed); 
      my.Changed += new EventHandler(my_Changed1); 

      my.Update(); 
      Console.ReadLine(); 
     } 

     static void my_Changed(object sender, EventArgs e) 
     { 
      Console.WriteLine("Hello"); 
     } 
     static void my_Changed1(object sender, EventArgs e) 
     { 
      Console.WriteLine("Hello1"); 
     } 
    } 
    public class MyObject 
    { 
     public MyObject() 
     { 
     } 
     private EventHandler ChangedEventHandler; 
     public event EventHandler Changed 
     { 
      add 
      { 
       ChangedEventHandler = value; 
      } 
      remove 
      { 
       ChangedEventHandler -= value; 
      } 
     } 
     public void Update() 
     { 
      OnChanged(); 
     } 

     private void OnChanged() 
     { 
      if (ChangedEventHandler != null) 
      { 
       ChangedEventHandler(this, null); 
      } 
     } 
    } 
} 
+4

bien, pour les lecteurs de vitesse qui l'ont manqué, c'est la ligne importante. ChangedEventHandler = valeur; au lieu de + =. Bon pour un usage unique seulement - pourrait fonctionner pour moi dans certains cas - merci! – ScottCate