2009-05-03 19 views
17

Come suggeriresti il ​​modo migliore di evitare abbonamenti di eventi duplicati? se questa riga di codice viene eseguita in due punti, l'evento verrà eseguito due volte. Sto cercando di evitare che gli eventi di terze parti vengano abbonati due volte.Evita abbonamenti di eventi duplicati in C#

theOBject.TheEvent += RunMyCode; 

Nel mio delegato setter, posso fare funzionare efficacemente questo ...

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

ma è che il modo migliore?

risposta

19

credo, il modo più efficace, è quello di rendere il vostro evento una proprietà e aggiungere serrature concorrenza ad essa come in questo 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 ha cambiato il suo dominio. Il nuovo URL è: http://codinglight.blogspot.com/2009/02/preventing-duplicate-subscriptions-to.html –

+0

FYI, se si ottiene un 503 al collegamento è sufficiente aggiornare la pagina. Sembrava caricare dopo alcuni tentativi per me. – Dan

1

Se si possiede l'origine per la classe dell'oggettoOggetto, è possibile accedere a InvocationList di TheEvent. È possibile implementare il proprio add accessor per l'evento e controllare prima di aggiungere.

Tuttavia, penso che anche il tuo approccio sia soddisfacente.

2

È il vostro codice multi threaded? Il blocco della concorrenza è necessario solo quando è multi-thread. Se non è un sovraccarico.

Come tale l'approccio di annullamento dell'iscrizione e di iscrizione è corretto.

Grazie

0

Uso il vostro approccio tranne un particolare. Penso che gli eventi dovrebbero essere sottoscritti quando crei una nuova istanza di subscriber o theObject, questo rende il codice più diretto. Quindi, tutto ciò di cui hai bisogno è solo guardare attentamente dopo che gli oggetti corretti sono stati eliminati (disporre il patten è una soluzione conveniente per questo).

Hai accennato al fatto che utilizzi un evento di terze parti, il che significa che non puoi fornire la tua realizzazione per i metodi di aggiunta/rimozione, come ti è stato consigliato. Ma nelle tue classi con i tuoi eventi devi definire la tua realizzazione di metodi di aggiunta/rimozione per l'evento per risolvere il tuo problema.

4

L'ho già fatto prima ... si presume che sia accettabile che venga chiamato l'ultimo utente.

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

bello, per quei lettori di velocità che potrebbero averlo perso, questa è la linea importante. ChangedEventHandler = valore; anziché + =. Buono solo per uso singolo - potrebbe funzionare per me in alcuni casi - grazie! – ScottCate

Problemi correlati