2 Stimmen

Wie wird eine verwaltete Ressource freigegeben, die nicht in den Müll wandert, wenn der Aufrufer vergisst, Dispose() zu verwenden?

In meinem Code habe ich eine Klasse, die einen neuen Thread erstellt. Dieser neue Thread hat einen Dispatcher, daher wird der Thread nicht beendet, es sei denn, ich rufe

Dispatcher.CurrentDispatcher.InvokeShutdown();

Der Thread kann nicht außerhalb meiner Klasse referenziert werden. Also dachte ich: Wie kann ich sicherstellen, dass mein Thread endet, wenn mein Objekt Garbage Collect ist?

Eine Antwort ist die Verwendung von IDisposable, aber wenn jemand vergisst, Dispose() aufzurufen, wird der Thread niemals anhalten, so dass dies keine Lösung ist.

Eine andere Antwort ist zwei verwenden Dispose + Destructor, aber ich habe gehört, dass wir nur den Destructor für Release unmanaged Ressource verwenden sollten. Ich bin in einer Sackgasse.

Was ist die beste Lösung?

2voto

Jon Skeet Punkte 1325502

Eine Möglichkeit ist, einen Finalizer nur für Debug-Builds zu verwenden. Lassen Sie den Thread nicht nur "netterweise" schließen, sondern protokollieren Sie eine Warnung an prominenter Stelle. Das sollte Ihnen helfen, die Stellen zu isolieren, an denen Sie vergessen haben, das Objekt ordnungsgemäß zu entsorgen.

Es ist jedoch nicht narrensicher und hat die unerwünschte Eigenschaft, dass sich der Debug- und der Release-Code unterscheiden.

Erhält Ihr Disponent normalerweise sehr häufig Ereignisse? Könnten Sie dafür sorgen, dass er zumindest eine Warnung ausgibt, wenn er längere Zeit keine Ereignisse empfangen hat?

Eine ziemlich unangenehme Option wäre es, dem Dispatcher einen schwachen Verweis auf das Wegwerfobjekt zu geben. Er könnte periodisch überprüfen, ob das Objekt garbage collected wurde (mit WeakReference.IsAlive ) und schaltet sich in diesem Fall selbst ab. Auch das ist nicht sehr angenehm (und sollte eine Warnung auslösen).

1voto

VladV Punkte 9703

Die Lösung "Dispose + Destructor" scheint mir in Ordnung zu sein. Sie könnten einige Tricks anwenden, wie Jon sagte, um zu erkennen, ob ein Dispose-Aufruf verpasst wurde, aber den Thread bei einem Finalizer-Aufruf anzuhalten, ist eine zusätzliche Sicherheit.

Übrigens, ein Thread ist eine nicht verwaltete Ressource.

1voto

IRBMe Punkte 4175

Es gibt eine Menge nützlicher Informationen über Dispose und Finalize aquí . Wenn Sie eine wiederverwendbare Klasse oder eine Bibliothek schreiben, die von anderen Programmierern verwendet werden soll, können Sie natürlich nicht davon ausgehen, dass die Dispose-Methode immer aufgerufen wird, und daher wäre es klug, einen Finalizer zu implementieren:

public void Dispose()  {
    Dispose(true);
    GC.SuppressFinalize(this); 
}

protected virtual void Dispose(bool disposing) {
    if (disposing) {
        // Free other state (managed objects).
    }
    // Free your own state (unmanaged objects).
    // Set large fields to null.
}

~MyClass() {
    Dispose (false);
}

Es scheint, dass dies nicht dass wiederverwendbar eine Klasse, die Sie schreiben, und ist ziemlich viel in Ihrem eigenen Programm verwendet. In diesem Fall haben Sie die folgenden Möglichkeiten:

  • Ressourcen werden im Finalizer aufgeräumt, wenn Dispose heißt nicht
  • Wie oben, aber zusätzlich wird eine Warnung oder ein Fehler protokolliert
  • Wenn der Finalizer aufgerufen wird, scheitert er laut

Sie können verhindern, dass die letzten beiden in die Veröffentlichung aufgenommen werden, indem Sie sie schützen:

~MyClass() {
    Dispose (false);
    #if DEBUG
        // log a warning or scream at the developer in some way
    #endif
}

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