5 Stimmen

Alle Event-Handler auf einmal entfernen

Problem: Ich habe eine Dokumentenklasse, die eine Liste von Objekten enthält. Diese Objekte lösen Ereignisse wie SolutionExpired, DisplayExpired usw. aus. Das Dokument muss darauf reagieren.

Dokumente können manchmal Objekte austauschen, aber ein einzelnes Objekt sollte niemals 'Teil' von mehr als einem Dokument sein.

Meine Dokumentenklasse enthält eine Reihe von Methoden, die als Ereignishandler dienen. Immer wenn ein Objekt in das Dokument eintritt, verwende ich AddHandler, um die Ereignisse einzurichten, und wenn ein Objekt aus dem Dokument entfernt wird, verwende ich RemoveHandler, um den Schaden rückgängig zu machen. Es gibt jedoch Fälle, in denen es schwierig ist sicherzustellen, dass alle Schritte ordnungsgemäß durchgeführt werden, und ich könnte daher mit rogue Ereignishandlern enden.

Langer Rede kurzer Sinn; wie entferne ich alle Handler, die auf eine bestimmte Methode zeigen? Beachten Sie, dass ich keine Liste potenzieller Ereignisquellen habe, diese könnten überall gespeichert sein.

So etwas wie:

RemoveHandler *.SolutionExpired, AddressOf DefObj_SolutionExpired

0 Stimmen

0 Stimmen

5voto

Ben Lesh Punkte 106494

Sie können Delegate.RemoveAll() verwenden. (Der Teil, der Sie interessiert, befindet sich in button2_Click)

public void Form_Load(object sender, EventArgs e) 
{ 
    button1.Click += new EventHandler(button1_Click);
    button1.Click += new EventHandler(button1_Click);
    button2.Click += new EventHandler(button2_Click);
    TestEvent += new EventHandler(Form_TestEvent);
}
event EventHandler TestEvent;
void OnTestEvent(EventArgs e)
{
    if (TestEvent != null)
        TestEvent(this, e);
}
void Form_TestEvent(object sender, EventArgs e)
{
    MessageBox.Show("TestEvent wurde ausgelöst");
}
void button2_Click(object sender, EventArgs e)
{
    Delegate d = TestEvent as Delegate;
    TestEvent = Delegate.RemoveAll(d, d) as EventHandler;
}
void button1_Click(object sender, EventArgs e)
{
    OnTestEvent(EventArgs.Empty);
}

Sie sollten beachten, dass es den Inhalt der Delegates, die Sie übergeben, nicht verändert. Es gibt stattdessen einen veränderten Delegate zurück. Daher können Sie die Ereignisse auf einem Button, den Sie auf einem Formular platziert haben, nicht vom Formular aus ändern, da button1.Click nur += oder -= verwendet werden können, nicht =. Dies wird nicht kompilieren:

button1.Click = Delegate.RemoveAll(d, d) as EventHandler;

Außerdem sollten Sie darauf achten, dass Sie potenzielle Rennbedingungen überwachen, egal wo Sie dies implementieren. Sie könnten ein wirklich seltsames Verhalten bekommen, wenn Sie Handler von einem Ereignis entfernen, das von einem anderen Thread aufgerufen wird!

1voto

Ben M Punkte 21694
public class TheAnswer
{
    public event EventHandler MyEvent = delegate { };

    public void RemoveFromMyEvent(string methodName)
    {
        foreach (var handler in MyEvent.GetInvocationList())
        {
            if (handler.Method.Name == methodName)
            {
                MyEvent -= (EventHandler)handler;
            }
        }
    }
}

EDIT 2: Entschuldigung für mein Missverständnis--ich sehe, dass Sie ziemlich klar gemacht haben, dass Sie keinen Zugriff auf die Ereignisquellen in Ihrem ursprünglichen Beitrag haben.

Der einfachste Weg, den ich mir vorstellen kann, um dieses Problem zu lösen, besteht darin, eine gemeinsame Dictionary von Objekt-zu-Dokument-Bindungen zu implementieren. Wenn ein Objekt in ein Dokument eintritt, überprüfen Sie das Dictionary auf eine vorhandene Bindung zu einem anderen Dokument; wenn vorhanden, entfernen Sie Handler, die auf das alte Dokument verweisen, bevor Sie sie für das neue hinzufügen. In jedem Fall aktualisieren Sie das Dictionary mit der neuen Bindung.

Ich denke, dass die Leistungs- und Speicherauswirkungen in den meisten Fällen vernachlässigbar wären: es sei denn, Sie haben es mit vielen Zehntausenden kleiner Objekte zu tun und tauschen sie häufig zwischen Dokumenten aus, sollte der Speicherüberkopf für jedes Schlüssel/Wert-Paar und der Leistungseinbruch für jede Suchoperation ziemlich gering sein.

Als Alternative: If you can detect (in the document event handlers) that the sender of the event is no longer relevant to the document, you can detach the events there.

Dies scheinen wie die Art von Ideen zu sein, die Sie bereits abgelehnt haben könnten--aber vielleicht auch nicht!

1voto

zproxy Punkte 3409

Verwenden Sie Delegate.RemoveAll (vielleicht unter Verwendung von Reflection, wenn die Delegatinstanz privat ist).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X