Come posso cancellare le iscrizioni agli eventi in C #?
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.
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;
}
}