it-swarm.com.de

Wie kann ich Ereignisabonnements in C # löschen?

Nehmen Sie die folgende C # -Klasse:

c1 {
 event EventHandler someEvent;
}

Wenn es viele Abonnements für das Ereignis someEvent von c1 Gibt und ich sie alle löschen möchte, wie kann dies am besten erreicht werden? Beachten Sie auch, dass Abonnements für dieses Ereignis Lambdas/anonyme Delegierte sein können/sind.

Derzeit ist meine Lösung, eine ResetSubscriptions() -Methode zu c1 Hinzuzufügen, die someEvent auf null setzt. Ich weiß nicht, ob dies irgendwelche ungesehenen Konsequenzen hat.

135
programmer

Innerhalb der Klasse können Sie die (versteckte) Variable auf null setzen. Eine Nullreferenz ist die kanonische Art, eine leere Aufrufliste effektiv darzustellen.

Von außerhalb der Klasse können Sie dies nicht tun - Ereignisse setzen im Grunde "abonnieren" und "abbestellen" und das wars.

Es lohnt sich, sich darüber im Klaren zu sein, was feldähnliche Ereignisse tatsächlich tun - sie erstellen gleichzeitig eine Variable und . Innerhalb der Klasse verweisen Sie schließlich auf die Variable. Von außen verweisen Sie auf das Ereignis.

Weitere Informationen finden Sie in meinem Artikel zu Veranstaltungen und Delegierten .

174
Jon Skeet

Fügen Sie c1 eine Methode hinzu, die 'someEvent' auf null setzt ...

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

Es ist besser, delegate {} als null zu verwenden

7
Feng

Um alle Abonnenten zu löschen, empfiehlt es sich, someEvent auf null zu setzen, indem Sie eine weitere öffentliche Methode hinzufügen, wenn Sie diese Funktionalität nach außen freigeben möchten. Dies hat keine ungesehenen Konsequenzen. Voraussetzung ist, dass Sie SomeEvent mit dem Schlüsselwort 'event' deklarieren.

Bitte lesen Sie das Buch - C # 4.0 auf den Punkt gebracht, Seite 125.

Jemand schlug hier vor, die Delegate.RemoveAll - Methode zu verwenden. Wenn Sie es verwenden, könnte der Beispielcode dem folgenden Formular folgen. Aber es ist wirklich blöd. Warum nicht einfach SomeEvent=null In der Funktion ClearSubscribers()?

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

Das Setzen des Ereignisses auf Null innerhalb der Klasse funktioniert. Wenn Sie eine Klasse entsorgen, sollten Sie das Ereignis immer auf null setzen, da der GC Probleme mit Ereignissen hat und die entsorgte Klasse möglicherweise nicht bereinigt, wenn sie baumelnde Ereignisse aufweist.

Sie erreichen dies mit den Methoden Delegate.Remove oder Delegate.RemoveAll.

5
Micah

Konzeptioneller erweiterter langweiliger Kommentar.

Ich verwende lieber den Word "Event Handler" anstelle von "Event" oder "Delegate". Und benutzte das Wort "Ereignis" für andere Sachen. In einigen Programmiersprachen (VB.NET, Object Pascal, Objective-C) wird "event" als "message" oder "signal" bezeichnet und verfügt sogar über ein "message" -Schlüsselwort und eine bestimmte Zuckersyntax.

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;

Und um auf diese "Nachricht" zu antworten, antwortet ein "Ereignishandler", unabhängig davon, ob es sich um einen einzelnen Delegaten oder mehrere Delegaten handelt.

Zusammenfassung: "Ereignis" ist die "Frage", "Ereignishandler" sind die Antwort (en).

3
umlcat

Das ist meine Lösung:

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

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

Sie müssen Dispose() aufrufen oder using(new Foo()){/*...*/} pattern verwenden, um alle Mitglieder der Aufrufliste abzumelden.

1
Jalal

Entfernen Sie alle Ereignisse. Nehmen Sie an, dass das Ereignis vom Typ "Aktion" ist:

Delegate[] dary = TermCheckScore.GetInvocationList();

if ( dary != null )
{
    foreach ( Delegate del in dary )
    {
        TermCheckScore -= ( Action ) del;
    }
}
0
Googol