1897 Stimmen

Richtige Verwendung der IDisposable-Schnittstelle

Ich weiß vom Lesen die Microsoft-Dokumentation dass die "primäre" Verwendung des IDisposable Schnittstelle ist es, nicht verwaltete Ressourcen zu bereinigen.

Für mich bedeutet "nicht verwaltet" Dinge wie Datenbankverbindungen, Sockets, Fensterhandles usw. Ich habe aber auch schon Code gesehen, bei dem die Dispose() Methode ist implementiert, um die verwaltet Ressourcen, was mir überflüssig erscheint, da der Garbage Collector dies für Sie erledigen sollte.

Zum Beispiel:

public class MyCollection : IDisposable
{
    private List<String> _theList = new List<String>();
    private Dictionary<String, Point> _theDict = new Dictionary<String, Point>();

    // Die, clear it up! (free unmanaged resources)
    public void Dispose()
    {
        _theList.clear();
        _theDict.clear();
        _theList = null;
        _theDict = null;
    }

Meine Frage ist, macht dies den Garbage Collector frei Speicher verwendet von MyCollection schneller als normalerweise?

edit : Bislang wurden einige gute Beispiele für die Verwendung von IDisposable zum Aufräumen von nicht verwalteten Ressourcen wie Datenbankverbindungen und Bitmaps vorgestellt. Aber nehmen wir an, dass _theList im obigen Code eine Million Zeichenfolgen enthielt und Sie diesen Speicher freigeben wollten jetzt anstatt auf den Garbage Collector zu warten. Würde der obige Code das erreichen?

2966voto

Ian Boyd Punkte 232380

Der Sinn von Dispose es um nicht verwaltete Ressourcen freizugeben. Dies muss zu einem bestimmten Zeitpunkt geschehen, da die Ressourcen sonst nie aufgeräumt werden. Der Garbage Collector weiß nicht wie anrufen DeleteHandle() auf eine Variable des Typs IntPtr weiß es nicht. ob oder nicht, muss es die DeleteHandle() .

Nota : Was ist ein unverwaltete Ressource ? Wenn Sie es im Microsoft .NET Framework gefunden haben: Es ist verwaltet. Wenn Sie selbst auf MSDN nachgeschaut haben, ist es nicht verwaltet. Alles, was Sie mit Hilfe von P/Invoke-Aufrufen außerhalb der netten, bequemen Welt von allem, was Ihnen im .NET Framework zur Verfügung steht, erreicht haben, ist nicht verwaltet - und Sie sind jetzt dafür verantwortlich, es zu bereinigen.

Das Objekt, das Sie erstellt haben, muss die einige Methode, die die Außenwelt aufrufen kann, um nicht verwaltete Ressourcen zu bereinigen. Die Methode kann beliebig benannt werden:

public void Cleanup()

ou

public void Shutdown()

Stattdessen gibt es aber eine standardisierte Bezeichnung für diese Methode:

public void Dispose()

Es wurde sogar eine Schnittstelle geschaffen, IDisposable die nur diese eine Methode hat:

public interface IDisposable
{
   void Dispose()
}

Sie machen also Ihr Objekt mit der IDisposable Schnittstelle, und auf diese Weise versprechen Sie, dass Sie diese eine Methode geschrieben haben, um Ihre nicht verwalteten Ressourcen zu bereinigen:

public void Dispose()
{
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);
}

Und schon sind Sie fertig. Aber Sie können es besser.


Was ist, wenn Ihr Objekt 250 MB zugewiesen hat? System.Drawing.Bitmap (d. h. die verwaltete .NET-Bitmap-Klasse) als eine Art Bildpuffer? Sicher, dies ist ein verwaltetes .NET-Objekt, und der Garbage Collector wird es freigeben. Aber wollen Sie wirklich 250 MB Speicher einfach so stehen lassen - und darauf warten, dass der Garbage Collector eventuell kommen und es befreien? Was, wenn es eine Datenbankverbindung öffnen ? Sicherlich wollen wir nicht, dass die Verbindung offen bleibt und darauf wartet, dass der GC das Objekt abschließt.

Wenn der Benutzer die Dispose() (d.h. sie planen nicht mehr, das Objekt zu verwenden), warum dann nicht diese verschwenderischen Bitmaps und Datenbankverbindungen loswerden?

Das werden wir jetzt tun:

  • nicht verwaltete Ressourcen loszuwerden (weil wir es müssen), und
  • Abschaffung der verwalteten Ressourcen (weil wir hilfreich sein wollen)

Aktualisieren wir also unsere Dispose() Methode, um diese verwalteten Objekte loszuwerden:

public void Dispose()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //Free managed resources too
   if (this.databaseConnection != null)
   {
      this.databaseConnection.Dispose();
      this.databaseConnection = null;
   }
   if (this.frameBufferImage != null)
   {
      this.frameBufferImage.Dispose();
      this.frameBufferImage = null;
   }
}

Und alles ist gut, außer Sie können es besser !


Was, wenn die Person vergessen anrufen Dispose() auf Ihr Objekt? Dann würden sie etwas auslaufen unverwaltet Ressourcen!

Nota: Sie werden nicht auslaufen verwaltet Ressourcen, denn schließlich wird der Garbage Collector in einem Hintergrund-Thread ausgeführt und gibt den Speicher für alle nicht verwendeten Objekte frei. Dazu gehören Ihr Objekt und alle verwalteten Objekte, die Sie verwenden (z. B. die Bitmap und die DbConnection ).

Wenn die Person vergessen hat, anzurufen Dispose() können wir immer noch Rette ihren Speck! Wir haben immer noch eine Möglichkeit, es zu nennen für sie: wenn der Garbage Collector endlich dazu kommt, unser Objekt freizugeben (d.h. zu finalisieren).

Nota: Der Garbage Collector wird schließlich alle verwalteten Objekte freigeben. Wenn er dies tut, ruft er die Finalize Methode auf das Objekt. Der GC weiß nicht, oder interessiert sich nicht für Ihr Entsorgen Sie Methode. Das war nur ein Name, den wir für eine Methode, die wir aufrufen, wenn wir nicht verwaltetes Zeug loswerden wollen.

Die Zerstörung unseres Objekts durch den Garbage Collector ist die perfekt Zeit, diese lästigen, nicht verwalteten Ressourcen freizugeben. Wir tun dies durch Überschreiben der Finalize() méthode.

Nota: In C# überschreiben Sie nicht explizit die Finalize() Methode. Sie schreiben eine Methode, die sieht aus wie a C++ Destruktor , und der Compiler geht davon aus, dass dies Ihre Implementierung der Finalize() Methode:

~MyObject()
{
    //we're being finalized (i.e. destroyed), call Dispose in case the user forgot to
    Dispose(); //<--Warning: subtle bug! Keep reading!
}

Aber es gibt einen Fehler in diesem Code. Sehen Sie, der Garbage Collector läuft auf einer Hintergrund-Thread Sie kennen die Reihenfolge, in der zwei Objekte zerstört werden, nicht. Es ist durchaus möglich, dass in Ihrem Dispose() Code, der verwaltet Der Gegenstand, den Sie loswerden wollten (weil Sie hilfreich sein wollten), ist nicht mehr da:

public void Dispose()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.gdiCursorBitmapStreamFileHandle);

   //Free managed resources too
   if (this.databaseConnection != null)
   {
      this.databaseConnection.Dispose(); //<-- crash, GC already destroyed it
      this.databaseConnection = null;
   }
   if (this.frameBufferImage != null)
   {
      this.frameBufferImage.Dispose(); //<-- crash, GC already destroyed it
      this.frameBufferImage = null;
   }
}

Was Sie also brauchen, ist eine Möglichkeit für Finalize() zu erzählen Dispose() dass sie keine verwalteten Ressourcen (weil sie vielleicht nicht da sein mehr), während gleichzeitig nicht verwaltete Ressourcen freigegeben werden.

Das Standardmuster hierfür ist, dass Finalize() y Dispose() rufen beide eine dritte (!)-Methode, bei der Sie einen booleschen Wert übergeben, der angibt, ob Sie die Methode von Dispose() (im Gegensatz zu Finalize() ), d.h. es ist sicher, verwaltete Ressourcen freizugeben.

Ce site intern Methode könnte einen willkürlichen Namen wie "CoreDispose" oder "MyInternalDispose" erhalten, aber es ist üblich, es als Dispose(Boolean) :

protected void Dispose(Boolean disposing)

Ein hilfreicherer Parametername könnte jedoch lauten:

protected void Dispose(Boolean itIsSafeToAlsoFreeManagedObjects)
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //Free managed resources too, but only if I'm being called from Dispose
   //(If I'm being called from Finalize then the objects might not exist
   //anymore
   if (itIsSafeToAlsoFreeManagedObjects)  
   {    
      if (this.databaseConnection != null)
      {
         this.databaseConnection.Dispose();
         this.databaseConnection = null;
      }
      if (this.frameBufferImage != null)
      {
         this.frameBufferImage.Dispose();
         this.frameBufferImage = null;
      }
   }
}

Und Sie ändern Ihre Implementierung der IDisposable.Dispose() Methode zu:

public void Dispose()
{
   Dispose(true); //I am calling you from Dispose, it's safe
}

und Ihren Finalizer an:

~MyObject()
{
   Dispose(false); //I am *not* calling you from Dispose, it's *not* safe
}

Nota : Wenn Ihr Objekt von einem Objekt abstammt, das die Funktion Dispose dann vergessen Sie nicht, ihre Basis Dispose-Methode, wenn Sie Dispose überschreiben:

public override void Dispose()
{
    try
    {
        Dispose(true); //true: safe to free managed resources
    }
    finally
    {
        base.Dispose();
    }
}

Und alles ist gut, außer Sie können es besser !


Ruft der Benutzer Dispose() auf Ihr Objekt, dann ist alles aufgeräumt. Später, wenn der Garbage Collector kommt und Finalize aufruft, ruft er dann Dispose encore.

Dies ist nicht nur verschwenderisch, sondern wenn Ihr Objekt Junk-Referenzen auf Objekte enthält, die Sie bereits aus der zuletzt Aufruf an Dispose() werden Sie versuchen, sie wieder zu entsorgen!

Sie werden feststellen, dass ich in meinem Code darauf geachtet habe, Verweise auf Objekte, die ich entsorgt habe, zu entfernen, so dass ich nicht versuche, die Dispose auf ein Junk-Objekt verweisen. Das hat aber nicht verhindert, dass sich ein subtiler Fehler eingeschlichen hat.

Wenn der Benutzer aufruft Dispose() : der Griff CursorFileBitmapIconServiceHandle zerstört wird. Später, wenn der Garbage Collector läuft, wird er versuchen, das gleiche Handle erneut zu zerstören.

protected void Dispose(Boolean iAmBeingCalledFromDisposeAndNotFinalize)
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle); //<--double destroy 
   ...
}

Sie können dies beheben, indem Sie dem Garbage Collector mitteilen, dass er sich nicht um die Finalisierung des Objekts kümmern muss - seine Ressourcen wurden bereits aufgeräumt, und es ist keine weitere Arbeit erforderlich. Sie tun dies durch den Aufruf GC.SuppressFinalize() im Dispose() Methode:

public void Dispose()
{
   Dispose(true); //I am calling you from Dispose, it's safe
   GC.SuppressFinalize(this); //Hey, GC: don't bother calling finalize later
}

Nachdem der Benutzer nun die Dispose() haben wir:

  • frei gewordene, nicht verwaltete Ressourcen
  • frei gewordene verwaltete Ressourcen

Es macht keinen Sinn, dass der GC den Finalizer ausführt - alles ist bereits erledigt.

Könnte ich nicht Finalize verwenden, um nicht verwaltete Ressourcen zu bereinigen?

Die Dokumentation für Object.Finalize sagt:

Die Finalize-Methode wird verwendet, um Aufräumarbeiten an nicht verwalteten Ressourcen durchzuführen, die vom aktuellen Objekt gehalten werden, bevor das Objekt zerstört wird.

Aber die MSDN-Dokumentation sagt auch, dass für IDisposable.Dispose :

Führt anwendungsdefinierte Aufgaben im Zusammenhang mit dem Freigeben, Freigeben oder Zurücksetzen von nicht verwalteten Ressourcen durch.

Welches ist es also? Welches ist der richtige Ort für mich, um nicht verwaltete Ressourcen zu bereinigen? Die Antwort ist:

Sie haben die Wahl! Aber wähle Dispose .

Sie können Ihre nicht verwaltete Bereinigung natürlich im Finalizer unterbringen:

~MyObject()
{
   //Free unmanaged resources
   Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);

   //A C# destructor automatically calls the destructor of its base class.
}

Das Problem dabei ist, dass Sie keine Ahnung haben, wann der Garbage Collector Ihr Objekt abschließen wird. Ihre nicht verwalteten, nicht benötigten und nicht genutzten nativen Ressourcen bleiben bestehen, bis der Garbage Collector eventuell läuft. Dann wird Ihre Finalizer-Methode aufgerufen, um nicht verwaltete Ressourcen zu bereinigen. Die Dokumentation von Object.Finalize weist auf Folgendes hin:

Der genaue Zeitpunkt, zu dem der Finalizer ausgeführt wird, ist nicht festgelegt. Um eine deterministische Freigabe von Ressourcen für Instanzen Ihrer Klasse zu gewährleisten, implementieren Sie eine Schließen Sie Methode oder bieten eine IDisposable.Dispose Umsetzung.

Dies ist der Vorzug der Verwendung von Dispose um nicht verwaltete Ressourcen zu bereinigen; Sie können wissen und kontrollieren, wann nicht verwaltete Ressourcen bereinigt werden. Ihre Zerstörung ist "deterministisch" .


Um Ihre ursprüngliche Frage zu beantworten: Warum wird der Speicher nicht jetzt freigegeben, sondern erst dann, wenn der GC dies beschließt? Ich habe eine Gesichtserkennungssoftware, die braucht um 530 MB interne Bilder loszuwerden jetzt da sie nicht mehr benötigt werden. Wenn wir das nicht tun, kommt die Maschine zum Stillstand.

Bonus Lesung

Für alle, denen der Stil dieser Antwort gefällt (Erläuterung der warum , so dass die wie deutlich wird), empfehle ich Ihnen die Lektüre von Kapitel eins des Buches Essential COM von Don Box:

Auf 35 Seiten erklärt er die Probleme bei der Verwendung binärer Objekte und erfindet vor Ihren Augen COM. Sobald Sie die warum von COM, die restlichen 300 Seiten sind offensichtlich und beschreiben lediglich die Implementierung von Microsoft.

Ich denke, jeder Programmierer, der sich jemals mit Objekten oder COM beschäftigt hat, sollte zumindest das erste Kapitel lesen. Es ist die beste Erklärung von allem überhaupt.

Extra Bonus Lektüre

Wenn alles, was du weißt, falsch ist Archiv von Eric Lippert

Es ist daher in der Tat sehr schwierig, einen korrekten Finalizer zu schreiben, und Der beste Rat, den ich Ihnen geben kann, ist, es nicht zu versuchen. .

84voto

yfeldblum Punkte 64211

IDisposable wird häufig zur Ausnutzung der using Anweisung und nutzen Sie die Vorteile einer einfachen Möglichkeit, verwaltete Objekte deterministisch zu bereinigen.

public class LoggingContext : IDisposable {
    public Finicky(string name) {
        Log.Write("Entering Log Context {0}", name);
        Log.Indent();
    }
    public void Dispose() {
        Log.Outdent();
    }

    public static void Main() {
        Log.Write("Some initial stuff.");
        try {
            using(new LoggingContext()) {
                Log.Write("Some stuff inside the context.");
                throw new Exception();
            }
        } catch {
            Log.Write("Man, that was a heavy exception caught from inside a child logging context!");
        } finally {
            Log.Write("Some final stuff.");
        }
    }
}

52voto

Scott Dorman Punkte 41206

Der Zweck des Dispose-Musters besteht darin, einen Mechanismus zur Verfügung zu stellen, mit dem sowohl verwaltete als auch nicht verwaltete Ressourcen bereinigt werden können, und wann dies geschieht, hängt davon ab, wie die Dispose-Methode aufgerufen wird. In Ihrem Beispiel hat die Verwendung von Dispose nichts mit Dispose zu tun, da das Löschen einer Liste keinen Einfluss auf die zu entsorgende Sammlung hat. Ebenso haben die Aufrufe zum Setzen der Variablen auf Null keine Auswirkungen auf die GC.

Sie können sich dies ansehen Artikel für weitere Details zur Implementierung des Dispose-Musters, aber im Grunde sieht es wie folgt aus:

public class SimpleCleanup : IDisposable
{
    // some fields that require cleanup
    private SafeHandle handle;
    private bool disposed = false; // to detect redundant calls

    public SimpleCleanup()
    {
        this.handle = /*...*/;
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources.
                if (handle != null)
                {
                    handle.Dispose();
                }
            }

            // Dispose unmanaged managed resources.

            disposed = true;
        }
    }

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

Die wichtigste Methode hier ist Dispose(bool), die unter zwei verschiedenen Umständen abläuft:

  • disposing == true: Die Methode wurde direkt oder indirekt durch den Code eines Benutzers aufgerufen. Verwaltete und nicht verwaltete Ressourcen können entsorgt werden.
  • disposing == false: Die Methode wurde von der Laufzeit innerhalb des Finalizers aufgerufen, und Sie sollten nicht auf andere Objekte verweisen. Nur nicht verwaltete Ressourcen können entsorgt werden.

Das Problem, wenn man die Aufräumarbeiten einfach der GC überlässt, ist, dass man keine wirkliche Kontrolle darüber hat, wann die GC einen Sammelzyklus durchführt (man kann GC.Collect() aufrufen, sollte es aber nicht tun), so dass die Ressourcen länger als nötig herumliegen können. Denken Sie daran, dass der Aufruf von Dispose() nicht wirklich einen Sammelzyklus auslöst oder die GC in irgendeiner Weise dazu veranlasst, das Objekt einzusammeln/freizugeben; er bietet lediglich die Möglichkeit, die verwendeten Ressourcen deterministischer aufzuräumen und der GC mitzuteilen, dass diese Aufräumarbeiten bereits durchgeführt wurden.

Der Sinn von IDisposable und dem Dispose-Muster besteht nicht darin, Speicher sofort freizugeben. Der einzige Fall, in dem ein Aufruf von Dispose überhaupt eine Chance hat, Speicher sofort freizugeben, ist, wenn er das Disposing == false Szenario behandelt und nicht verwaltete Ressourcen manipuliert. Bei verwaltetem Code wird der Speicher erst wieder freigegeben, wenn die GC einen Sammelzyklus durchführt, worauf Sie keinen Einfluss haben (außer dem Aufruf von GC.Collect(), was, wie bereits erwähnt, keine gute Idee ist).

Ihr Szenario ist nicht wirklich gültig, da Strings in .NET keine unveränderten Ressourcen verwenden und IDisposable nicht implementieren, gibt es keine Möglichkeit, sie zu zwingen, "aufgeräumt" werden.

24voto

Daniel Earwicker Punkte 111630

Nach dem Aufruf von Dispose sollte es keine weiteren Aufrufe der Methoden eines Objekts geben (obwohl ein Objekt weitere Aufrufe von Dispose tolerieren sollte). Daher ist das Beispiel in der Frage unsinnig. Wenn Dispose aufgerufen wird, kann das Objekt selbst entsorgt werden. Der Benutzer sollte also einfach alle Verweise auf das gesamte Objekt verwerfen (auf null setzen), und alle damit verbundenen internen Objekte werden automatisch aufgeräumt.

Was die allgemeine Frage nach verwalteten/unverwalteten Ressourcen und die Diskussion in anderen Antworten anbelangt, so denke ich, dass jede Antwort auf diese Frage mit einer Definition einer nicht verwalteten Ressource beginnen muss.

Es gibt eine Funktion, die Sie aufrufen können, um das System in einen bestimmten Zustand zu versetzen, und eine andere Funktion, die Sie aufrufen können, um es wieder aus diesem Zustand herauszubringen. In einem typischen Beispiel könnte die erste Funktion eine Funktion sein, die ein Dateihandle zurückgibt, und die zweite Funktion könnte ein Aufruf von CloseHandle .

Aber - und das ist der springende Punkt - es kann sich dabei um jedes beliebige Paar von Funktionen handeln. Die eine baut einen Zustand auf, die andere reißt ihn ab. Wenn der Zustand zwar aufgebaut, aber noch nicht abgebaut wurde, dann existiert eine Instanz der Ressource. Sie müssen dafür sorgen, dass der Abriss zum richtigen Zeitpunkt erfolgt - die Ressource wird nicht von der CLR verwaltet. Der einzige automatisch verwaltete Ressourcentyp ist der Speicher. Es gibt zwei Arten: den GC und den Stack. Werttypen werden vom Stack verwaltet (oder indem sie sich in Referenztypen einklinken), und Referenztypen werden von der GC verwaltet.

Diese Funktionen können Zustandsänderungen verursachen, die frei verschachtelt werden können, oder sie müssen perfekt verschachtelt sein. Die Zustandsänderungen können thread-sicher sein oder auch nicht.

Sehen Sie sich das Beispiel in der Frage von Justice an. Änderungen an der Einrückung der Protokolldatei müssen perfekt verschachtelt sein, sonst geht alles schief. Außerdem ist es unwahrscheinlich, dass sie thread-sicher sind.

Es ist möglich, mit dem Müllsammler mitzufahren, um Ihre nicht verwalteten Ressourcen zu bereinigen. Aber nur, wenn die Zustandsänderungsfunktionen thread-sicher sind und zwei Zustände Lebenszeiten haben können, die sich in irgendeiner Weise überschneiden. Das Beispiel einer Ressource von Justice darf also KEINEN Finalizer haben! Das würde einfach niemandem helfen.

Für diese Art von Ressourcen können Sie einfach die IDisposable ohne einen Finalisierer. Der Finalisator ist absolut optional - er muss es sein. Dies wird in vielen Büchern übergangen oder gar nicht erst erwähnt.

Sie müssen dann die using Erklärung, um zu gewährleisten, dass Dispose genannt wird. Dies ist im Wesentlichen wie eine Fahrt mit dem Stack (so wie Finalizer ist, um die GC, using auf dem Stapel ist).

Der fehlende Teil ist, dass Sie Dispose manuell schreiben müssen und es auf Ihre Felder und Ihre Basisklasse aufrufen müssen. C++/CLI-Programmierer müssen das nicht tun. Der Compiler schreibt es in den meisten Fällen für sie.

Es gibt eine Alternative, die ich für Zustände bevorzuge, die perfekt verschachtelt und nicht thread-sicher sind (abgesehen von allem anderen, erspart die Vermeidung von IDisposable Ihnen das Problem, einen Streit mit jemandem zu haben, der nicht widerstehen kann, jeder Klasse, die IDisposable implementiert, einen Finalizer hinzuzufügen).

Anstatt eine Klasse zu schreiben, schreiben Sie eine Funktion. Die Funktion nimmt einen Delegaten an, der zurückgerufen wird:

public static void Indented(this Log log, Action action)
{
    log.Indent();
    try
    {
        action();
    }
    finally
    {
        log.Outdent();
    }
}

Und dann wäre da noch ein einfaches Beispiel:

Log.Write("Message at the top");
Log.Indented(() =>
{
    Log.Write("And this is indented");

    Log.Indented(() =>
    {
        Log.Write("This is even more indented");
    });
});
Log.Write("Back at the outermost level again");

Das Lambda, das übergeben wird, dient als Codeblock, d.h. es ist so, als ob Sie Ihre eigene Kontrollstruktur erstellen, die demselben Zweck dient wie using nur mit dem Unterschied, dass keine Gefahr mehr besteht, dass der Anrufer sie missbraucht. Er kann auf keinen Fall versäumen, die Ressource zu bereinigen.

Diese Technik ist weniger nützlich, wenn die Ressource von der Art ist, die sich überschneidende Lebenszeiten haben kann, weil man dann in der Lage sein möchte, Ressource A zu bauen, dann Ressource B, dann Ressource A zu töten und später Ressource B zu töten. Aber dann müssen Sie IDisposable (aber immer noch ohne einen Finalizer, es sei denn, Sie haben Threadsafety implementiert, was nicht kostenlos ist).

18voto

olli-MSFT Punkte 2546

Szenarien, in denen ich IDisposable verwende: Aufräumen nicht verwalteter Ressourcen, Abbestellen von Ereignissen, Schließen von Verbindungen

Das Idiom, das ich für die Implementierung von IDisposable ( nicht thread-sicher ) :

class MyClass : IDisposable {
    // ...

    #region IDisposable Members and Helpers
    private bool disposed = false;

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

    private void Dispose(bool disposing) {
        if (!this.disposed) {
            if (disposing) {
                // cleanup code goes here
            }
            disposed = true;
        }
    }

    ~MyClass() {
        Dispose(false);
    }
    #endregion
}

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