2008-10-06 13 views
5

Dies ist etwas, das ich nie in .NET als die korrekte Anwendung der .dispose() -Methode vollständig begriffen hat.Was ist die beste Anwendung von. Dispose()

Sagen, ich habe so etwas wie

Public Class someClass() 
    sub someMethod 
    ' do some stuff tying up resources 
    end sub 
End Class 

public class mainApp 
    dim _class as new SomeClass 
    _class.someMethod() 
End Class 

In allen Fällen ist es sinnvoll, eine dispose-Methode, und wenn ja, zu implementieren, was da drin gehen sollte?

Wenn es nicht der Fall ist, dass jede Klasse Entsorgungsmethode haben sollte (was mein Bauchgefühl sagt, sollte das nicht) welche Klassen sollten? Ich habe immer gedacht, dass alles, was eine Ressource binden kann (d. H. Verbindung, Datenleser usw.), eine .dispose() haben sollte, die diese Ressourcen nicht zuordnen würde.

Auch wie würden Sie einen Aufruf zum Aufrufen der. Dispose() -Methode erzwingen?

Antwort

5

Ich empfehle dringend zu lesen Cleaning Up Unmanaged Resources auf MSDN, es hat Artikel zu berühren wann Dispose zu verwenden und IDisposable korrekt zu implementieren. Ihr Bauchgefühl ist größtenteils korrekt, da Sie IDisposable nur selten implementieren müssen, es sei denn, Ihre Klasse verwendet nicht verwaltete Ressourcen oder ist ein Container für ein Objekt, das IDisposable implementiert.

Um den Aufruf von Dispose zu erzwingen, fügen Sie bei der ordnungsgemäßen Implementierung der IDisposable-Schnittstelle einen Finalizer hinzu, der Dispose aufruft, um die Nachzügler und abweichenden Klassen zu fangen, die vergessen haben.

Relevante Artikel:

Implementing a Dispose Method

Beschreibt die Implementierung der Dispose-Methode für nicht verwalteten Ressourcen freigeben.

Using Objects That Encapsulate Resources

Beschreiben Möglichkeiten, dass die Dispose-Methode, um sicherzustellen, wie die C# using-Anweisung (Verwendung in Visual Basic) genannt.

(edit: zusätzliche Informationen hinzugefügt)

In Ihrem Beispiel haben Sie SomeClass.SomeMethod, die etwas Arbeit tut, vermutlich mit einer Ressource. Wenn diese Ressource kein Mitglied der Klasse ist, können Sie sie besser in einem using-statement umhüllen und die teuflischen Details von IDisposable vergessen.

Public Class someClass() 
    sub someMethod 
    Using someResource As New ResourceType(arguments) 
     ' no worries about IDisposable for someResource, as it is automatic 
    End Using 
    end sub 
End Class 
+0

Ich würde auch sehr empfehlen einen Artikel mit dem Titel "IDisposable: Was Ihre Mutter Ihnen nie über Ressourcenfreigabe erzählt" unter http://www.codeproject.com/KB/dotnet/IDisposable.aspx - obwohl es Ihnen das Gefühl geben könnte, dass die Verwendung von IDisposable absolut korrekt ist, ist es fast hoffnungslos. –

0

Die Methode Dispose() wird für die frühzeitige Bereinigung von Ressourcen verwendet. Obwohl der Garbage Collector für Sie keinen ungenutzten Speicher zurückgewinnt, liegt es an Ihnen, sich mit Dingen wie Netzwerk-/Datenbankverbindungen und Dateigriffen zu befassen. Normalerweise möchten Sie diese Dinge freigegeben werden, sobald sie nicht mehr benötigt werden, also implementieren Sie das Wegwerfmuster und nutzen Sie die Using Anweisung für den Aufruf in einem try/finally Block hinter den Kulissen.

0

Im Allgemeinen sollten Sie IDisposable implementieren, wenn Ihre Klasse beabsichtigt, etwas zu öffnen.Ob es sich um ein Handle zu einer Datei, eine Verbindung zu einer Datenbank oder eine Ressource handelt, die einen großen Teil des Speichers belegt oder die Anwendung in einem instabilen Zustand belässt, es ist immer eine gute Idee IDisposable zu implementieren, um den Code zu spezifizieren SCHLIESSEN Sie diese Ressourcen.

Sie können andere Entwickler nicht zwingen, Ihre Dispose-Methoden aufzurufen, aber IDisposable automatisch implementieren bedeutet, dass wir die Using-Anweisung verwenden können; was, wenn Sie sich einmal angewöhnt haben, ist schwer zu brechen :)

1

Es gibt viele falsche Informationen über IDisposable. Es ist ein PATTERN, das hilft, das zu erreichen, was früher über einen Destruktor in C++ erreicht wurde. Das Problem ist, dass in .NET die Zerstörung eines Objekts nicht deterministisch ist (es passiert nicht automatisch, wenn ein Objekt den Gültigkeitsbereich verlässt, sondern zum Zeitpunkt der Garbage Collection, die sich in einem separaten Thread mit niedriger Priorität befindet).

Sie müssen Dispose nicht implementieren, es sei denn, Sie haben eine Ressource, die auf irgendeine Weise freigegeben werden muss. Wenn beispielsweise Ihre privaten Datenmitglieder Dispose implementieren, sollten Sie wahrscheinlich auch Dispose implementieren und Dispose für diese privaten Mitglieder in Ihrem Dispose aufrufen. Ebenso sollten Sie alle PInvoke-Handles in Dispose freigeben.

Auch die Dispose-Methode wird bei der Garbage Collection NICHT automatisch für Sie aufgerufen. Dies ist das größte Stück Fehlinformation. Sie müssen Dispose von Ihrem Destruktor (C#) oder Finalize (VB.NET) aufrufen. Hier ist ein gutes Muster Entsorgen für die Umsetzung:

public class Foo : IDisposable 
{ 
    public Foo() 
    { 
     // Allocate some resource here 
    } 

    ~Foo() 
    { 
     Dispose(false); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
    } 

    private void Dispose(bool disposing) 
    { 
     // De-allocate resource here 
     if (disposing) 
     GC.SuppressFinalize(this); 
    } 
} 

Der Grund, dass Sie anrufen GC.SupressFinalize ist, dass, wenn das Objekt einen Finalizer hat, das Objekt tatsächlich auf die nächste GC Generation gefördert werden, weil es zu nennen hat Schließen Sie das erste Mal ab, wenn der GC ausgeführt wird, und können Sie Ihr Objekt erst freigeben, wenn die Finalisierung abgeschlossen ist. Daher wird der Speicher erst beim zweiten Durchlauf des GC freigegeben. Wenn Sie Dispose manuell aufrufen, können Sie den Finalizer überspringen, sodass Ihr Objekt beim ersten Durchlauf des GC freigegeben wird.

Um den größtmöglichen Nutzen aus Entsorgen zu erhalten, verwenden Sie die Verwendung von keword:

using (Foo f = new Foo()) 
{ 
    // Do something with Foo 
} 

Dies ist genau das gleiche wie wenn Sie dies geschrieben hatte:

Foo f; 
try 
{ 
    f = new Foo(); 
    // Do something with Foo 
} 
finally 
{ 
    f.Dispose(); 
} 

Einige Leute ein setzen möchten Boolean in ihrer Klasse namens _disposed, und dann überprüfen Sie, dass Bool während jedes Methodenaufrufs und eine Ausnahme auslösen, wenn Sie versuchen, eine Methode für ein Objekt aufzurufen, nachdem Dispose aufgerufen wird. Für interne Projektklassen halte ich diesen Overkill im Allgemeinen für sinnvoll, aber es könnte eine gute Sache sein, wenn Sie eine Bibliothek für den Verbrauch von Drittanbietern erstellen.

+0

Normalerweise, wenn ich etwas entsorge, setze ich es sofort auf Null. Auf diese Weise kann der Finalizer überprüfen, ob er null ist, anstatt ein extra spezielles boolesches Flag zu haben. –

+0

Hm, es scheint, dass alles, was Sie gesagt haben, gegen das von Microsoft empfohlene Entwurfsmuster für die IDisposable-Implementierung ist. Daher würde die Verwendung Ihrer Empfehlung in Konflikt mit der Verwendung und Aufrufen von Dispose, Dispose (Disposing) und Finalize durch Microsoft stehen. -1 – AMissico

+0

@AMissico? Wie das? Es sieht so aus, als ob sie ziemlich nah beieinander sind. Ich habe möglicherweise nicht kopiert und eingefügt Microsoft-Code, das Muster ist das gleiche. – Nick

0

Sie sollten IDisposable in einer Klasse implementieren, wenn die Klasse entweder:

  • einige andere Objekte besitzen implementieren die IDisposable
  • wie P/Invoke einige Ressourcen durch eine nicht verwaltete Schnittstelle zuordnet.
Verwandte Themen