Finalisieren vs Entsorgen

Antworten:

120

Andere haben bereits den Unterschied zwischen Disposeund behandelt Finalize(übrigens wird die FinalizeMethode in der Sprachspezifikation immer noch als Destruktor bezeichnet), daher möchte ich nur ein wenig zu den Szenarien hinzufügen, in denen die FinalizeMethode nützlich ist.

Einige Typen kapseln verfügbare Ressourcen so, dass sie einfach zu verwenden sind, und entsorgen sie in einer einzigen Aktion. Die allgemeine Verwendung ist oft wie folgt: Öffnen, Lesen oder Schreiben, Schließen (Entsorgen). Es passt sehr gut zum usingKonstrukt.

Andere sind etwas schwieriger. WaitEventHandlesZum Beispiel werden Instanzen nicht so verwendet, da sie verwendet werden, um von einem Thread zu einem anderen zu signalisieren. Es stellt sich dann die Frage, wer diese anrufen soll Dispose. Als Schutz implementieren solche Typen eine FinalizeMethode, die sicherstellt, dass Ressourcen verfügbar sind, wenn die Instanz nicht mehr von der Anwendung referenziert wird.

Brian Rasmussen
quelle
60
Ich konnte diese genehmigte Antwort nicht verstehen. Ich möchte immer noch das andere wissen. Was es ist?
Ismael
22
@Ismael: Die größte Situation, Finalizedie gerechtfertigt sein kann, ist, wenn es eine Reihe von Objekten gibt, die daran interessiert sind, eine Ressource am Leben zu erhalten, aber es gibt keine Möglichkeit, mit der ein Objekt, das nicht mehr an der Ressource interessiert ist, herausfinden kann, ob es die ist Letzter. In diesem Fall Finalizewird normalerweise nur ausgelöst, wenn sich niemand für das Objekt interessiert. Das lose Timing von Finalizeist für nicht fungible Ressourcen wie Dateien und Sperren schrecklich, für fungible Ressourcen jedoch möglicherweise in Ordnung.
Supercat
13
+1 an Supercat für ein tolles neues (für mich) Wort. Der Kontext machte es ziemlich klar, aber nur für den Rest von uns, hier ist, was Wikipedia sagt: "Fungibilität ist das Eigentum eines Gutes oder einer Ware, deren einzelne Einheiten zur gegenseitigen Substitution fähig sind, wie süßes Rohöl ein Unternehmen, Anleihen, Edelmetalle oder Währungen. "
Jon Coombs
5
@ JonCoombs: Das ist ziemlich richtig, obwohl es erwähnenswert sein kann, dass der Begriff "fungible Ressource" auf Dinge angewendet wird, die frei substituierbar sind, bis sie erworben werden und nach Freigabe oder Aufgabe wieder frei substituierbar werden . Wenn das System über einen Pool von Sperrobjekten verfügt und Code eines erwirbt, das es einer Entität zuordnet , kann diese Sperre möglicherweise nicht durch diese Sperre ersetzt werden , solange jemand einen Verweis auf diese Sperre zum Zwecke der Zuordnung zu dieser Entität hält jede andere. Wenn jedoch der gesamte Code, der sich um die geschützte Entität kümmert, die Sperre aufgibt, ...
Supercat
... dann würde es wieder frei substituierbar werden, bis es mit einer anderen Entität verbunden ist.
Supercat
135

Die Finalizer-Methode wird aufgerufen, wenn Ihr Objekt durch Müll gesammelt wird und Sie keine Garantie haben, wann dies geschehen wird (Sie können es erzwingen, aber es beeinträchtigt die Leistung).

Die DisposeMethode hingegen soll von dem Code aufgerufen werden, der Ihre Klasse erstellt hat, damit Sie alle Ressourcen, die Sie erworben haben (nicht verwaltete Daten, Datenbankverbindungen, Dateihandles usw.), bereinigen und freigeben können, sobald der Code fertig ist Ihr Objekt.

Die Standardpraxis besteht darin, zu implementieren IDisposableund DisposeIhr Objekt in einer usingAnweisung zu verwenden. Wie zum Beispiel using(var foo = new MyObject()) { }. Und in Ihrem Finalizer rufen Sie an Dispose, nur für den Fall, dass der aufrufende Code vergessen hat, über Sie zu verfügen.

Samuel
quelle
17
Sie müssen etwas vorsichtig sein, wenn Sie Dispose aus Ihrer Finalize-Implementierung aufrufen. Dispose kann auch verwaltete Ressourcen entsorgen, die Sie von Ihrem Finalizer nicht berühren möchten, da diese möglicherweise bereits selbst finalisiert wurden.
Itowlson
6
@itowlson: Die Überprüfung auf Null in Kombination mit der Annahme, dass Objekte zweimal entsorgt werden können (wobei der zweite Aufruf nichts bewirkt), sollte ausreichend sein.
Samuel
7
Das Standard-IDisposal-Muster und die versteckte Implementierung eines Dispose (Bool) zur optionalen Entsorgung verwalteter Komponenten scheinen dieses Problem zu lösen.
Brody
Es hört sich so an, als gäbe es keinen Grund, den Destruktor (die ~ MyClass () -Methode) zu implementieren und stattdessen immer die Dispose () -Methode zu implementieren und aufzurufen. Oder liege ich falsch? Könnte mir jemand ein Beispiel geben, wenn beide implementiert werden sollten?
dpelisek
66

Finalize ist die Backstop-Methode, die vom Garbage Collector aufgerufen wird, wenn ein Objekt zurückgefordert wird. Dispose ist die "deterministische Bereinigungsmethode", die von Anwendungen aufgerufen wird, um wertvolle native Ressourcen (Fensterhandles, Datenbankverbindungen usw.) freizugeben, wenn sie nicht mehr benötigt werden, anstatt sie unbegrenzt zu belassen, bis der GC das Objekt erreicht.

Als Benutzer eines Objekts verwenden Sie immer Dispose. Finalisieren ist für den GC.

Wenn Sie als Implementierer einer Klasse verwaltete Ressourcen besitzen, die entsorgt werden sollen, implementieren Sie Dispose. Wenn Sie native Ressourcen besitzen, implementieren Sie sowohl Dispose als auch Finalize und rufen beide eine gemeinsame Methode auf, mit der die nativen Ressourcen freigegeben werden. Diese Redewendungen werden normalerweise durch eine private Dispose-Methode (Bool Disposing) kombiniert, bei der Aufrufe mit true entsorgt und Aufrufe mit false abgeschlossen werden. Diese Methode gibt immer native Ressourcen frei, überprüft dann den Dispositionsparameter. Wenn dies zutrifft, werden verwaltete Ressourcen entsorgt und GC.SuppressFinalize aufgerufen.

itowlson
quelle
2
Das ursprünglich empfohlene Muster für Klassen, die eine Mischung aus selbstreinigenden ("verwalteten") und nicht selbstreinigenden ("nicht verwalteten") Ressourcen enthielten, ist seit langem veraltet. Ein besseres Muster besteht darin, jede nicht verwaltete Ressource separat in ein eigenes verwaltetes Objekt zu verpacken, das keine starken Verweise auf etwas enthält, das für die Bereinigung nicht erforderlich ist. Für alles, auf das ein finalisierbares Objekt eine direkte oder indirekte starke Referenz enthält, wird die GC-Lebensdauer verlängert. Wenn Sie die Dinge zusammenfassen, die für die Bereinigung benötigt werden, können Sie vermeiden, die GC-Lebensdauer von Dingen zu verlängern, die dies nicht sind.
Supercat
2
@JCoombs: Disposeist gut und die korrekte Implementierung ist im Allgemeinen einfach. Finalizeist böse und es richtig zu implementieren ist im Allgemeinen schwierig. Da der GC sicherstellt, dass die Identität eines Objekts niemals "recycelt" wird, solange ein Verweis auf dieses Objekt vorhanden ist, ist es unter anderem einfach, eine Reihe von DisposableObjekten zu bereinigen, von denen einige möglicherweise bereits bereinigt wurden kein Problem; Jede Referenz auf ein Objekt, auf das Disposebereits aufgerufen wurde, bleibt eine Referenz auf ein Objekt, auf das Disposebereits aufgerufen wurde.
Supercat
2
@JCoombs: Nicht verwaltete Ressourcen haben im Allgemeinen keine solche Garantie. Wenn das Objekt Freddas Dateihandle Nr. 42 besitzt und es schließt, hängt das System möglicherweise dieselbe Nummer an das Dateihandle an, das einer anderen Entität zugewiesen wird. In diesem Fall bezieht sich das Dateihandle Nr. 42 nicht auf Freds geschlossene Datei, sondern auf die Datei, die von dieser anderen Entität aktiv verwendet wurde. denn Fredzu versuchen, Griff Nr. 42 wieder zu schließen, wäre katastrophal. Der Versuch, zu 100% zuverlässig zu verfolgen, ob ein nicht verwaltetes Objekt noch freigegeben wurde, ist praktikabel. Der Versuch, mehrere Objekte im Auge zu behalten, ist viel schwieriger.
Supercat
2
@JCoombs: Wenn jede nicht verwaltete Ressource in einem eigenen Wrapper-Objekt platziert ist, das nur ihre Lebensdauer steuert, dann außerhalb des Codes, der nicht weiß, ob die Ressource freigegeben wurde, aber weiß, dass dies der Fall sein sollte, wenn dies noch nicht geschehen ist kann das Wrapper-Objekt sicher auffordern, es freizugeben; Das Wrapper-Objekt weiß, ob es dies getan hat, und kann die Anforderung ausführen oder ignorieren. Die Tatsache, dass der GC garantiert, dass ein Verweis auf den Wrapper immer ein gültiger Verweis auf den Wrapper ist, ist eine sehr nützliche Garantie.
Supercat
43

Finalisieren

  • Finalizer sollten immer sein protected, nicht publicoder privateso, dass die Methode nicht direkt aus dem Code der Anwendung aufgerufen werden kann und gleichzeitig die base.FinalizeMethode aufrufen kann
  • Finalizer sollten nur nicht verwaltete Ressourcen freigeben.
  • Das Framework garantiert nicht, dass ein Finalizer auf einer bestimmten Instanz überhaupt ausgeführt wird.
  • Weisen Sie niemals Speicher in Finalisierern zu und rufen Sie niemals virtuelle Methoden von Finalisierern auf.
  • Vermeiden Sie die Synchronisierung und das Auslösen nicht behandelter Ausnahmen in den Finalisierern.
  • Die Ausführungsreihenfolge von Finalisierern ist nicht deterministisch. Mit anderen Worten, Sie können sich nicht darauf verlassen, dass noch ein anderes Objekt in Ihrem Finalisierer verfügbar ist.
  • Definieren Sie keine Finalizer für Werttypen.
  • Erstellen Sie keine leeren Destruktoren. Mit anderen Worten, Sie sollten niemals explizit einen Destruktor definieren, es sei denn, Ihre Klasse muss nicht verwaltete Ressourcen bereinigen, und wenn Sie eine definieren, sollte sie einige Arbeit leisten. Wenn Sie später nicht mehr nicht verwaltete Ressourcen im Destruktor bereinigen müssen, entfernen Sie sie vollständig.

Entsorgen

  • Implementieren Sie IDisposableauf jedem Typ, der einen Finalizer hat
  • Stellen Sie sicher, dass ein Objekt nach dem Aufruf der DisposeMethode unbrauchbar wird. Vermeiden Sie mit anderen Worten die Verwendung eines Objekts, nachdem die DisposeMethode darauf aufgerufen wurde.
  • Rufen Sie Disposealle IDisposableTypen an, sobald Sie damit fertig sind
  • Ermöglicht Disposedas mehrfache Aufrufen ohne Fehler.
  • Unterdrücken Sie spätere Aufrufe des Finalizers aus der DisposeMethode heraus mit der GC.SuppressFinalizeMethode
  • Vermeiden Sie die Erstellung von verfügbaren Werttypen
  • Vermeiden Sie es, Ausnahmen innerhalb von DisposeMethoden auszulösen

Entsorgen / Finalisiertes Muster

  • Microsoft empfiehlt, dass Sie beide implementieren Disposeund Finalizemit nicht verwalteten Ressourcen arbeiten. Die FinalizeImplementierung würde ausgeführt und die Ressourcen würden weiterhin freigegeben, wenn das Objekt durch Müll gesammelt wird, selbst wenn ein Entwickler es versäumt hätte, die DisposeMethode explizit aufzurufen .
  • Bereinigen Sie die nicht verwalteten Ressourcen in der FinalizeMethode sowie in der DisposeMethode. Rufen Sie außerdem die DisposeMethode für alle .NET-Objekte, die Sie als Komponenten in dieser Klasse haben (mit nicht verwalteten Ressourcen als Mitglied), aus der DisposeMethode auf.
GenZiy
quelle
17
Ich lese überall dieselbe Antwort und kann immer noch nicht verstehen, was der Zweck eines jeden ist. Ich lese nur Regeln nach Regeln, nichts weiter.
Ismael
@Ismael: und auch der Autor fügt nichts hinzu, außer das Kopieren und Einfügen von Text aus MSDN.
Tarik
@ Tarik Ich habe es bereits gelernt. Ich hatte eine "Versprechen" -Konzeption, als ich dies fragte.
Ismael
31

Finalize wird vom GC aufgerufen, wenn dieses Objekt nicht mehr verwendet wird.

Dispose ist nur eine normale Methode, die der Benutzer dieser Klasse aufrufen kann, um Ressourcen freizugeben.

Wenn der Benutzer vergessen hat, Dispose aufzurufen, und wenn die Klasse Finalize implementiert hat, stellt GC sicher, dass sie aufgerufen wird.

Bhushan Bhangale
quelle
3
Die sauberste Antwort aller Zeiten
Dariogriffo
19

Es gibt einige Schlüssel aus dem Buch MCSD Certification Toolkit (Prüfung 70-483) Seite 193:

destructor ≈ (fast gleich)base.Finalize() , Der Destructor wird in eine Override-Version der Finalize-Methode konvertiert, die den Code des Destructors ausführt und dann die Finalize-Methode der Basisklasse aufruft. Dann ist es völlig nicht deterministisch, dass Sie nicht wissen können, wann aufgerufen wird, da dies von der GC abhängt.

Wenn eine Klasse keine verwalteten Ressourcen und keine nicht verwalteten Ressourcen enthält , sollte sie keinen IDisposableDestruktor implementieren oder haben.

Wenn die Klasse nur Ressourcen verwaltet hat , sollte sie implementiert werden, IDisposableaber keinen Destruktor haben. (Wenn der Destruktor ausgeführt wird, können Sie nicht sicher sein, ob verwaltete Objekte noch vorhanden sind, daher können Sie ihre Dispose()Methoden sowieso nicht aufrufen .)

Wenn die Klasse nur über nicht verwaltete Ressourcen verfügt , muss sie implementiert werden IDisposableund benötigt einen Destruktor, falls das Programm nicht aufruft Dispose().

Dispose()Methode muss sicher sein, um mehr als einmal ausgeführt zu werden. Sie können dies erreichen, indem Sie eine Variable verwenden, um zu verfolgen, ob sie zuvor ausgeführt wurde.

Dispose()sollte sowohl verwaltete als auch nicht verwaltete Ressourcen freigeben .

Der Destruktor sollte nur nicht verwaltete Ressourcen freigeben . Wenn der Destruktor ausgeführt wird, können Sie nicht sicher sein, ob verwaltete Objekte noch vorhanden sind, sodass Sie ihre Dispose-Methoden ohnehin nicht aufrufen können. Dies wird mithilfe des kanonischen protected void Dispose(bool disposing)Musters erreicht, bei dem nur verwaltete Ressourcen freigegeben (entsorgt) werden, wenn disposing == true.

Nach dem Freigeben von Ressourcen Dispose()sollte aufgerufen werdenGC.SuppressFinalize , damit das Objekt die Finalisierungswarteschlange überspringen kann.

Ein Beispiel für eine Implementierung für eine Klasse mit nicht verwalteten und verwalteten Ressourcen:

using System;

class DisposableClass : IDisposable
{
    // A name to keep track of the object.
    public string Name = "";

    // Free managed and unmanaged resources.
    public void Dispose()
    {
        FreeResources(true);

        // We don't need the destructor because
        // our resources are already freed.
        GC.SuppressFinalize(this);
    }

    // Destructor to clean up unmanaged resources
    // but not managed resources.
    ~DisposableClass()
    {
        FreeResources(false);
    }

    // Keep track if whether resources are already freed.
    private bool ResourcesAreFreed = false;

    // Free resources.
    private void FreeResources(bool freeManagedResources)
    {
        Console.WriteLine(Name + ": FreeResources");
        if (!ResourcesAreFreed)
        {
            // Dispose of managed resources if appropriate.
            if (freeManagedResources)
            {
                // Dispose of managed resources here.
                Console.WriteLine(Name + ": Dispose of managed resources");
            }

            // Dispose of unmanaged resources here.
            Console.WriteLine(Name + ": Dispose of unmanaged resources");

            // Remember that we have disposed of resources.
            ResourcesAreFreed = true;
        }
    }
}
MirlvsMaximvs
quelle
2
Das ist eine schöne Antwort! Aber ich denke, das ist falsch: "Der Destruktor sollte GC.SuppressFinalize aufrufen". Sollte die öffentliche Dispose () -Methode nicht stattdessen GC.SuppressFinalize aufrufen? Siehe: docs.microsoft.com/en-us/dotnet/api/… Durch Aufrufen dieser Methode wird verhindert, dass der Garbage Collector Object.Finalize aufruft (das vom Destruktor überschrieben wird).
Ewa
7

In 99% der Fälle sollten Sie sich auch keine Sorgen machen müssen. :) Wenn Ihre Objekte jedoch Verweise auf nicht verwaltete Ressourcen enthalten (z. B. Fensterhandles, Dateihandles), müssen Sie Ihrem verwalteten Objekt eine Möglichkeit bieten, diese Ressourcen freizugeben. Finalize gibt implizite Kontrolle über die Freigabe von Ressourcen. Es wird vom Garbage Collector aufgerufen. Dispose ist eine Möglichkeit, die Freigabe von Ressourcen explizit zu steuern, und kann direkt aufgerufen werden.

Es gibt noch viel mehr über das Thema Garbage Collection zu lernen , aber das ist ein Anfang.

JP Alioto
quelle
5
Ich bin mir ziemlich sicher , dass mehr als 1% von C # -Anwendungen verwenden Datenbanken: wo Sie haben über IDisposable SQL Sachen zu kümmern.
Samuel
1
Außerdem sollten Sie IDisposable implementieren, wenn Sie IDisposables kapseln. Was wahrscheinlich die anderen 1% abdeckt.
Darren Clark
@ Samuel: Ich sehe nicht, was Datenbanken damit zu tun haben. Wenn Sie über das Schließen von Verbindungen sprechen, ist das in Ordnung, aber das ist eine andere Sache. Sie müssen keine Objekte entsorgen, um Verbindungen rechtzeitig zu schließen.
JP Alioto
1
@JP: Aber das Using (...) -Muster macht es so viel einfacher, damit umzugehen.
Brody
2
Einverstanden, aber genau das ist der Punkt. Das Verwendungsmuster verbirgt den Aufruf, für Sie zu entsorgen.
JP Alioto
6

Der Finalizer dient zur impliziten Bereinigung. Sie sollten diese Option immer dann verwenden, wenn eine Klasse Ressourcen verwaltet, die unbedingt bereinigt werden müssen , da sonst Handles / Speicher usw. verloren gehen würden.

Die korrekte Implementierung eines Finalizers ist notorisch schwierig und sollte nach Möglichkeit vermieden werden. Die SafeHandleKlasse (verfügbar in .Net v2.0 und höher) bedeutet jetzt, dass Sie einen Finalizer nur noch sehr selten (wenn überhaupt) mehr implementieren müssen.

Die IDisposableBenutzeroberfläche dient zur expliziten Bereinigung und wird viel häufiger verwendet. Sie sollten diese verwenden, damit Benutzer Ressourcen explizit freigeben oder bereinigen können, wenn sie ein Objekt nicht mehr verwenden.

Beachten Sie, dass Sie bei einem Finalizer auch die IDisposableSchnittstelle implementieren sollten , damit Benutzer diese Ressourcen explizit früher freigeben können, als dies bei einer Speicherbereinigung des Objekts der Fall wäre.

Unter DG Update: Entsorgung, Finalisierung und Ressourcenverwaltung finden Sie die meiner Meinung nach besten und vollständigsten Empfehlungen zu Finalisierern und IDisposable.

Justin
quelle
3

Die Zusammenfassung lautet -

  • Sie schreiben einen Finalizer für Ihre Klasse, wenn er auf nicht verwaltete Ressourcen verweist, und Sie möchten sicherstellen, dass diese nicht verwalteten Ressourcen freigegeben werden, wenn eine Instanz dieser Klasse automatisch durch Speicherbereinigung erfasst wird . Beachten Sie, dass Sie den Finalizer eines Objekts nicht explizit aufrufen können - er wird vom Garbage Collector automatisch aufgerufen, wenn dies als notwendig erachtet wird.
  • Auf der anderen Seite implementieren Sie die IDisposable-Schnittstelle (und definieren folglich die Dispose () -Methode als Ergebnis für Ihre Klasse), wenn Ihre Klasse auf nicht verwaltete Ressourcen verweist, aber nicht darauf warten möchten, dass der Garbage Collector aktiviert wird (kann jederzeit sein - nicht unter der Kontrolle des Programmierers) und möchten diese Ressourcen freigeben, sobald Sie fertig sind. Auf diese Weise können Sie nicht verwaltete Ressourcen explizit freigeben, indem Sie die Dispose () -Methode eines Objekts aufrufen.

Ein weiterer Unterschied besteht darin, dass Sie in der Dispose () -Implementierung auch verwaltete Ressourcen freigeben sollten , während dies im Finalizer nicht erfolgen sollte. Dies liegt daran, dass es sehr wahrscheinlich ist, dass die verwalteten Ressourcen, auf die das Objekt verweist, bereits bereinigt wurden, bevor es finalisiert werden kann.

Für eine Klasse, die nicht verwaltete Ressourcen verwendet, empfiehlt es sich, sowohl die Dispose () -Methode als auch den Finalizer als Fallback zu definieren, falls ein Entwickler vergisst, das Objekt explizit zu entsorgen. Beide können eine gemeinsam genutzte Methode verwenden, um verwaltete und nicht verwaltete Ressourcen zu bereinigen:

class ClassWithDisposeAndFinalize : IDisposable
{
    // Used to determine if Dispose() has already been called, so that the finalizer
    // knows if it needs to clean up unmanaged resources.
     private bool disposed = false;

     public void Dispose()
     {
       // Call our shared helper method.
       // Specifying "true" signifies that the object user triggered the cleanup.
          CleanUp(true);

       // Now suppress finalization to make sure that the Finalize method 
       // doesn't attempt to clean up unmanaged resources.
          GC.SuppressFinalize(this);
     }
     private void CleanUp(bool disposing)
     {
        // Be sure we have not already been disposed!
        if (!this.disposed)
        {
             // If disposing equals true i.e. if disposed explicitly, dispose all 
             // managed resources.
            if (disposing)
            {
             // Dispose managed resources.
            }
             // Clean up unmanaged resources here.
        }
        disposed = true;
      }

      // the below is called the destructor or Finalizer
     ~ClassWithDisposeAndFinalize()
     {
        // Call our shared helper method.
        // Specifying "false" signifies that the GC triggered the cleanup.
        CleanUp(false);
     }
JBelfort
quelle
2

Das beste Beispiel, das ich kenne.

 public abstract class DisposableType: IDisposable
  {
    bool disposed = false;

    ~DisposableType()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(false);
      }
    }

    public void Dispose()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(true);
        GC.SuppressFinalize(this);
      }
    }

    public void Close()
    {
      Dispose();
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposing) 
      {
        // managed objects
      }
      // unmanaged objects and resources
    }
  }
isxaker
quelle
2

Unterschied zwischen Finalize- und Dispose-Methoden in C #.

GC ruft die Finalize-Methode auf, um die nicht verwalteten Ressourcen (wie Dateibetrieb, Windows-API, Netzwerkverbindung, Datenbankverbindung) zurückzugewinnen. Die Zeit ist jedoch nicht festgelegt, wann GC sie aufrufen würde. Es wird von GC implizit aufgerufen, was bedeutet, dass wir keine Kontrolle auf niedriger Ebene haben.

Entsorgungsmethode: Wir haben eine niedrige Kontrolle darüber, wie wir es aus dem Code aufrufen. Wir können die nicht verwalteten Ressourcen zurückfordern, wenn wir der Meinung sind, dass sie nicht verwendbar sind. Wir können dies erreichen, indem wir das IDisposal-Muster implementieren.

Sheo Dayal Singh
quelle
1

Klasseninstanzen enthalten häufig die Kontrolle über Ressourcen, die nicht von der Laufzeit verwaltet werden, z. B. Fensterhandles (HWND), Datenbankverbindungen usw. Daher sollten Sie sowohl eine explizite als auch eine implizite Möglichkeit zum Freigeben dieser Ressourcen bereitstellen. Stellen Sie implizite Kontrolle bereit, indem Sie die geschützte Finalize-Methode für ein Objekt implementieren (Destruktorsyntax in C # und die verwalteten Erweiterungen für C ++). Der Garbage Collector ruft diese Methode irgendwann auf, nachdem keine gültigen Verweise mehr auf das Objekt vorhanden sind. In einigen Fällen möchten Sie Programmierern, die ein Objekt verwenden, möglicherweise die Möglichkeit geben, diese externen Ressourcen explizit freizugeben, bevor der Garbage Collector das Objekt freigibt. Wenn eine externe Ressource knapp oder teuer ist, kann eine bessere Leistung erzielt werden, wenn der Programmierer Ressourcen explizit freigibt, wenn sie nicht mehr verwendet werden. Implementieren Sie die Dispose-Methode, die von der IDisposable-Schnittstelle bereitgestellt wird, um eine explizite Steuerung bereitzustellen. Der Konsument des Objekts sollte diese Methode aufrufen, wenn das Objekt verwendet wird. Dispose kann auch dann aufgerufen werden, wenn andere Verweise auf das Objekt vorhanden sind.

Beachten Sie, dass Sie auch dann eine implizite Bereinigung mithilfe der Finalize-Methode bereitstellen sollten, wenn Sie eine explizite Steuerung über Dispose bereitstellen. Finalize bietet eine Sicherung, um zu verhindern, dass Ressourcen dauerhaft verloren gehen, wenn der Programmierer Dispose nicht aufruft.

Sanjeev Pundir
quelle
1

Der Hauptunterschied zwischen Dispose und Finalize besteht darin, dass:

Disposewird normalerweise von Ihrem Code aufgerufen. Die Ressourcen werden sofort freigegeben, wenn Sie es aufrufen. Die Leute vergessen, die Methode aufzurufen, also wird die using() {}Aussage erfunden. Wenn Ihr Programm die Ausführung des Codes innerhalb von beendet hat {}, wird es aufgerufenDispose automatisch Methode auf.

Finalizewird von Ihrem Code nicht aufgerufen. Es soll vom Garbage Collector (GC) aufgerufen werden. Dies bedeutet, dass die Ressource in Zukunft jederzeit freigegeben werden kann, wenn GC dies beschließt. Wenn GC seine Arbeit erledigt, werden viele Finalize-Methoden durchlaufen. Wenn Sie eine starke Logik haben, wird dies den Prozess verlangsamen. Dies kann zu Leistungsproblemen für Ihr Programm führen. Seien Sie also vorsichtig mit dem, was Sie dort eingeben.

Ich persönlich würde den größten Teil der Zerstörungslogik in Dispose schreiben. Hoffentlich klärt dies die Verwirrung.

Tim Hong
quelle
-1

Wie wir wissen, werden Dispose und Finalize verwendet, um nicht verwaltete Ressourcen freizugeben. Der Unterschied besteht jedoch darin, dass Finalize zwei Zyklen zum Freigeben der Ressourcen verwendet, während Dispose einen Zyklus verwendet.

Surin Panda
quelle
Entsorgen gibt die Ressource sofort frei. Finalize kann die Ressource mit einem gewissen Grad an Aktualität freigeben oder nicht.
Supercat
1
Ah, er meint wahrscheinlich, dass "ein finalisierbares Objekt vom GC zweimal erkannt werden muss, bevor sein Speicher wiederhergestellt
aeroson
-4

Um auf den ersten Teil zu antworten, sollten Sie Beispiele bereitstellen, bei denen Personen für genau dasselbe Klassenobjekt unterschiedliche Ansätze verwenden. Ansonsten ist es schwierig (oder sogar seltsam) zu antworten.

Was die zweite Frage betrifft, lesen Sie besser zuerst diese ordnungsgemäße Verwendung der IDisposable-Schnittstelle, die dies behauptet

Es ist deine Wahl! Aber wählen Sie Entsorgen.

Mit anderen Worten: Der GC kennt nur den Finalizer (falls vorhanden. Wird Microsoft auch als Destruktor bezeichnet). Ein guter Code versucht, beide zu bereinigen (Finalizer und Dispose).

ilias iliadis
quelle