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?

5voto

Arjan Einbu Punkte 13269

Wenn überhaupt, würde ich erwarten, dass der Code wie folgt lautet weniger effizienter, als wenn sie weggelassen wird.

Der Aufruf der Clear()-Methoden ist unnötig, und der GC würde das wahrscheinlich nicht tun, wenn Dispose es nicht tun würde...

5voto

Pragmateek Punkte 12920

Abgesehen von seiner primären Verwendung als Mittel zur Kontrolle der Lebensdauer de Systemressourcen (vollständig abgedeckt durch die ehrfürchtige Antwort von Ian , Hut ab!), die IDEinweg/Verwendung combo kann auch verwendet werden, um den Umfang der Zustandsänderung von (kritischen) globalen Ressourcen : die Konsole die Gewinde die Prozess jede globales Objekt wie ein Anwendungsinstanz .

Ich habe einen Artikel über dieses Muster geschrieben: http://pragmateek.com/c-scope-your-global-state-changes-with-idisposable-and-the-using-statement/

Es zeigt, wie Sie einige häufig verwendete globale Zustände in einer wiederverwendbar y lesbar Art und Weise: Konsolenfarben , aktuell Fadenkultur , Eigenschaften von Excel-Anwendungsobjekten ...

4voto

MikeJ Punkte 1144

Ich sehe, dass viele Antworten auf die Verwendung von IDisposable für verwaltete und nicht verwaltete Ressourcen übergegangen sind. Ich würde diesen Artikel als eine der besten Erklärungen empfehlen, die ich gefunden habe, wie IDisposable tatsächlich verwendet werden sollte.

https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About

Für die eigentliche Frage; sollten Sie IDisposable verwenden, um verwaltete Objekte zu bereinigen, die eine Menge Speicher belegen, wäre die kurze Antwort sein keine . Der Grund dafür ist, dass Ihr Objekt, das den Speicher hält, aus dem Geltungsbereich herausgeht und zur Abholung bereit ist. Zu diesem Zeitpunkt sind alle referenzierten untergeordneten Objekte ebenfalls außerhalb des Anwendungsbereichs und werden abgeholt.

Die einzige wirkliche Ausnahme wäre, wenn Sie eine Menge Speicher in verwalteten Objekten gebunden haben und Sie diesen Thread blockiert haben, während Sie auf den Abschluss einer Operation warten. Wenn diese Objekte nach Beendigung des Aufrufs nicht mehr benötigt werden, könnte das Setzen dieser Referenzen auf null dem Garbage Collector ermöglichen, sie früher einzusammeln. Aber dieses Szenario würde schlechten Code darstellen, der überarbeitet werden müsste - kein Anwendungsfall für IDisposable.

3voto

Adam Speight Punkte 682

IDisposable eignet sich für die Abmeldung von Veranstaltungen.

3voto

CharithJ Punkte 44196

Das von Ihnen angegebene Codebeispiel ist kein gutes Beispiel für IDisposable Verwendung. Wörterbuchbereinigung normalerweise sollte nicht zum Dispose Methode. Wörterbucheinträge werden geleert und entsorgt, wenn sie den Anwendungsbereich verlassen. IDisposable Implementierung ist erforderlich, um einige Speicher/Handler freizugeben, die auch dann nicht freigegeben werden, wenn sie den Anwendungsbereich verlassen haben.

Das folgende Beispiel zeigt ein gutes Beispiel für das IDisposable-Muster mit etwas Code und Kommentaren.

public class DisposeExample
{
    // A base class that implements IDisposable. 
    // By implementing IDisposable, you are announcing that 
    // instances of this type allocate scarce resources. 
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource. 
        private IntPtr handle;
        // Other managed resource this class uses. 
        private Component component = new Component();
        // Track whether Dispose has been called. 
        private bool disposed = false;

        // The class constructor. 
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable. 
        // Do not make this method virtual. 
        // A derived class should not be able to override this method. 
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method. 
            // Therefore, you should call GC.SupressFinalize to 
            // take this object off the finalization queue 
            // and prevent finalization code for this object 
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios. 
        // If disposing equals true, the method has been called directly 
        // or indirectly by a user's code. Managed and unmanaged resources 
        // can be disposed. 
        // If disposing equals false, the method has been called by the 
        // runtime from inside the finalizer and you should not reference 
        // other objects. Only unmanaged resources can be disposed. 
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called. 
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources. 
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up 
                // unmanaged resources here. 
                // If disposing is false, 
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;

            }
        }

        // Use interop to call the method necessary 
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# destructor syntax for finalization code. 
        // This destructor will run only if the Dispose method 
        // does not get called. 
        // It gives your base class the opportunity to finalize. 
        // Do not provide destructors in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here. 
            // Calling Dispose(false) is optimal in terms of 
            // readability and maintainability.
            Dispose(false);
        }
    }
    public static void Main()
    {
        // Insert code here to create 
        // and use the MyResource object.
    }
}

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