Domanda

Prendi la seguente classe C #:

c1 {
 event EventHandler someEvent;
}

Se ci sono molti abbonamenti all'evento c1 someEvent e desidero cancellarli tutti, qual è il modo migliore per raggiungere questo obiettivo? Considera anche che le iscrizioni a questo evento potrebbero essere / sono lambdas / delegati anonimi.

Attualmente la mia soluzione è aggiungere un metodo ResetSubscriptions () a c1 che imposta someEvent su null. Non so se ciò abbia conseguenze invisibili.

È stato utile?

Soluzione

Dall'interno della classe, è possibile impostare la variabile (nascosta) su null. Un riferimento null è il modo canonico di rappresentare un elenco di invocazioni vuoto, in modo efficace.

Al di fuori della classe, non puoi farlo: gli eventi sostanzialmente espongono " iscriviti " e "annullare l'iscrizione" e basta.

Vale la pena essere consapevoli di cosa stanno realmente facendo eventi simili a un campo: stanno creando una variabile e un evento allo stesso tempo. All'interno della classe, si finisce per fare riferimento alla variabile. Dall'esterno, fai riferimento all'evento.

Vedi il mio articolo su eventi e delegati per ulteriori informazioni.

Altri suggerimenti

Aggiungi un metodo a c1 che imposterà 'someEvent' su null ...

class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = null;}
}
class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = delegate{};}
}

È meglio usare il delegato {} piuttosto che null

L'impostazione dell'evento su null all'interno della classe funziona. Quando disponi una classe, dovresti sempre impostare l'evento su null, il GC ha problemi con gli eventi e potrebbe non ripulire la classe eliminata se ha eventi sospesi.

La migliore pratica per cancellare tutti gli abbonati è di impostare null su someEvent aggiungendo un altro metodo pubblico se si desidera esporre questa funzionalità all'esterno. Ciò non ha conseguenze invisibili. Il presupposto è ricordare di dichiarare SomeEvent con la parola chiave "evento".

Si prega di consultare il libro - C # 4.0 in breve, pagina 125.

Qualcuno qui ha proposto di utilizzare il metodo Delegate.RemoveAll . Se lo usi, il codice di esempio potrebbe seguire il modulo seguente. Ma è davvero stupido. Perché non solo SomeEvent = null all'interno della funzione ClearSubscribers () ?

   public void ClearSubscribers ()
    {
          SomeEvent = (EventHandler) Delegate.RemoveAll(SomeEvent, SomeEvent);// Then you will find SomeEvent is set to null.
    }

Puoi farlo utilizzando i metodi Delegate.Remove o Delegate.RemoveAll.

Commento noioso esteso concettuale.

Preferisco usare la parola "gestore di eventi" invece di " evento " o "delegare". E ho usato la parola "evento" per altre cose. In alcuni linguaggi di programmazione (VB.NET, Object Pascal, Objective-C), "event" viene chiamato " messaggio " o "segnale", e persino avere un "messaggio" parola chiave e sintassi specifica dello zucchero.

const
  WM_Paint = 998;  // <-- "question" can be done by several talkers
  WM_Clear = 546;

type
  MyWindowClass = class(Window)
    procedure NotEventHandlerMethod_1;
    procedure NotEventHandlerMethod_17;

    procedure DoPaintEventHandler; message WM_Paint; // <-- "answer" by this listener
    procedure DoClearEventHandler; message WM_Clear;
  end;

E, per rispondere a quel "messaggio", un "gestore di eventi" rispondere, che sia un singolo delegato o più delegati.

Sommario: & Quot; Event " è la "domanda", "gestore / i di eventi"; sono le risposte.

Questa è la mia soluzione:

public class Foo : IDisposable
{
    private event EventHandler _statusChanged;
    public event EventHandler StatusChanged
    {
        add
        {
            _statusChanged += value;
        }
        remove
        {
            _statusChanged -= value;
        }
    }

    public void Dispose()
    {
        _statusChanged = null;
    }
}

Devi chiamare Dispose () o usare usando (new Foo ()) {/*...*/} pattern per annullare l'iscrizione a tutti i membri dell'elenco di invocazioni .

Rimuovi tutti gli eventi, supponi che l'evento sia un " Azione " Tipo:

Delegate[] dary = TermCheckScore.GetInvocationList();

if ( dary != null )
{
    foreach ( Delegate del in dary )
    {
        TermCheckScore -= ( Action ) del;
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top