72 Stimmen

Müssen Sie einen Ereignishandler im Destruktor entfernen?

Ich verwende einige UserControls die in meiner Anwendung während der Laufzeit erstellt und zerstört werden (durch Erstellen und Schließen von Unterfenstern mit diesen Steuerelementen darin).
Es ist ein WPF UserControl und erbt von System.Windows.Controls.UserControl . Es gibt keine Dispose() Methode, die ich außer Kraft setzen könnte.
PPMM ist eine Singleton mit der gleichen Lebensdauer wie meine Anwendung.
Jetzt im Konstruktor meiner (WPF) UserControl füge ich einen Event-Handler hinzu:

public MyControl()
{
    InitializeComponent();

    // hook up to an event
    PPMM.FactorChanged += new ppmmEventHandler(PPMM_FactorChanged);
}

Ich habe mir angewöhnt, solche Ereignishandler im Destruktor zu entfernen:

~MyControl()
{
    // hook off of the event
    PPMM.FactorChanged -= new ppmmEventHandler(PPMM_FactorChanged);
}

Heute bin ich über diesen Artikel gestolpert und habe mich gewundert:

1) Ist dies notwendig? Oder kümmert sich der GC darum?

2) Funktioniert das überhaupt? Oder müsste ich die neu erstellte ppmmEventHandler ?

Ich bin gespannt auf Ihre Antworten.

2voto

dowhilefor Punkte 10822

Der GC wird sich darum kümmern. Das Ereignis hält zwar eine starke Referenz, aber nur für das übergeordnete Objekt selbst. Am Ende wird nur MyControl einen Verweis über den Ereignishandler behalten, so dass der GC ihn sammeln wird.

Andererseits wird der Finalizer verwendet, der KEIN Deskriptor ist. Ist für diese schlechte Praxis. Wenn Sie die Registrierung eines Ereignisses aufheben wollen, sollten Sie IDisposable .

1voto

Event-Handler sind trickreich und können leicht ein Ressourcenleck verbergen. Wie Tigran sagt. Verwenden Sie IDisposeable und vergessen Sie Destruktoren. Ich empfehle zu messen, ob Sie es richtig gemacht haben. Ein Blick auf den Speicherverbrauch Ihrer Anwendung im Task-Manager reicht aus, um festzustellen, ob ein Leck vorliegt, wenn Sie einen kleinen Stresstest durchführen, indem Sie ein paar Tausend Fenster laden und schließen.

1voto

supercat Punkte 72939

Es gibt einige Fälle, in denen die Abmeldung von einem Ereignis in einem Finalizer/Destructor nützlich sein könnte, wenn der Herausgeber des Ereignisses garantiert, dass die Abmeldung fadenfrei ist . Damit ein Objekt sich von seinem Abonnement abmelden kann eigene Ereignisse wären nutzlos, aber man könnte als praktikables Muster ein öffentliches Objekt einen Verweis auf ein privates Objekt halten lassen, das tatsächlich "die ganze Arbeit macht", und dieses private Objekt Ereignisse abonnieren lassen. Wenn es keinen Verweis vom privaten Objekt zurück zum öffentlichen Objekt gibt, kommt das öffentliche Objekt für die Finalisierung in Frage, sobald sich niemand mehr dafür interessiert; sein Finalisierer wäre dann in der Lage, das Abonnement im Namen des privaten Objekts zu beenden.

Leider kann dieses Muster nur funktionieren, wenn die Objekte, deren Ereignisse abonniert werden, garantieren, dass sie Abmeldeanforderungen aus jedem Threading-Kontext akzeptieren können und nicht nur aus dem Kontext, in dem die Ereignisse abonniert wurden. Wenn .NET als Teil des "Ereignis"-Vertrags vorschreibt, dass alle Abmeldemethoden thread-sicher sein müssen, wäre dies keine große Belastung für die Implementierungen, aber aus welchen Gründen auch immer hat MS eine solche Anforderung nicht gestellt. Folglich gibt es, selbst wenn ein Finalizer/Destructor feststellt, dass ein Ereignis so schnell wie möglich abbestellt werden sollte, keinen Standardmechanismus, mit dem er dies erreichen kann.

0voto

Sascha Punkte 9970

2) Das funktioniert

1) Ich hatte einen Fall (mit einem In-App-Nachrichtendienst), bei dem Event-Handler für ein globales Objekt nicht freigegeben wurden und der GC das Objekt deshalb nicht sammeln konnte. Ich denke, dies ist in der Regel eine seltene Bedingung - mit einem Profiler wie ANTS von red gate können Sie leicht ein Speicher-Profiling durchführen, wenn Sie denken, dass dies bei Ihnen passiert.

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