Finalize / Dispose-Muster in C #
C# 2008
Habe ich die Arbeit auf diesem für eine Weile jetzt, und ich bin immer noch verwirrt über einige Probleme. Meine Fragen sind unten
- Ich weiß, dass Sie nur finalizer, wenn Sie die Entsorgung von nicht verwalteten Ressourcen. Allerdings, wenn Sie mit verwalteten Ressourcen, die Anrufe zu nicht verwalteten Ressourcen, würden Sie noch brauchen, um einen finalizer implementieren?
- Jedoch, wenn Sie entwickeln eine Klasse, die nicht alle nicht verwalteten Ressourcen, direkt oder indirekt, können Sie implementieren die
IDisposable
so, dass die clients Ihrer Klasse verwenden können, die 'Anweisung'?Wäre es akzeptabel, implementiert die IDisposable-gerade so, dass Kunden von Ihrer Klasse können die using-Anweisung?
using(myClass objClass = new myClass()) { //Do stuff here }
- Entwickelt ich diese einfach folgenden code zeigen Sie die Finalize/dispose-Muster:
public class NoGateway : IDisposable { private WebClient wc = null; public NoGateway() { wc = new WebClient(); wc.DownloadStringCompleted += wc_DownloadStringCompleted; } //Start the Async call to find if NoGateway is true or false public void NoGatewayStatus() { //Start the Async's download //Do other work here wc.DownloadStringAsync(new Uri(www.xxxx.xxx)); } private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { //Do work here } //Dispose of the NoGateway object public void Dispose() { wc.DownloadStringCompleted -= wc_DownloadStringCompleted; wc.Dispose(); GC.SuppressFinalize(this); } }
Frage zum Quelltext:
- Hier habe ich nicht Hinzugefügt haben, die Sie in Gang gesetzt, und in der Regel der finalizer aufgerufen wird von GC, und der finalizer wird die Dispose. Da ich nicht der finalizer, wenn ich die Dispose-Methode aufrufen? Ist es der client der Klasse, die es zu nennen?
Also meine Klasse ist die im Beispiel genannte NoGateway und der client verwenden könnte, und entsorgen Sie die Klasse wie folgt aus:
using(NoGateway objNoGateway = new NoGateway()) { //Do stuff here }
Würden die Dispose-Methode automatisch aufgerufen, wenn die Ausführung erreicht das Ende des using-block, oder muss der client manuell aufrufen der dispose-Methode? also
NoGateway objNoGateway = new NoGateway(); //Do stuff with object objNoGateway.Dispose(); //finished with it
- Ich bin mit der webclient-Klasse in meinem
NoGateway
Klasse. Da der webclient implementiert die IDisposable-Schnittstelle, bedeutet dies, dass der webclient indirekt verwendet, nicht verwaltete Ressourcen? Gibt es eine harte und schnelle Regel Folgen diese? Woher weiß ich, dass eine Klasse nicht verwaltete Ressourcen verwendet?
InformationsquelleAutor der Frage ant2009 | 2009-05-22
Du musst angemeldet sein, um einen Kommentar abzugeben.
Empfohlen IDisposable-pattern ist hier. Bei der Programmierung eine Klasse, die IDisposable verwendet, in der Regel sollten Sie die Verwendung von zwei mustern:
Sich bei der Umsetzung einer versiegelten Klasse, der nicht verwaltete Ressourcen, die man einfach implementieren einer Dispose-Methode als mit normalen interface-Implementierungen:
Bei der Umsetzung eine nicht versiegelte Klasse, machen Sie es wie diese:
Bemerken, dass ich noch nicht erklärt, ein finalizer im
B
; Sie sollte nur einen finalizer implementieren, wenn Sie tatsächlich nicht verwaltete Ressourcen zu verfügen. Der CLR beschäftigt sich mit beendbar Objekte anders zu nicht-beendbar Objekte, auch wennSuppressFinalize
genannt wird.So, Sie sollten nicht erklären, einen finalizer, wenn Sie zu haben, aber Sie geben die Erben Ihrer Klasse einen Haken zu rufen, Ihre
Dispose
und einen finalizer implementieren, selbst wenn Sie nicht verwaltete Ressourcen direkt:Wenn du nicht mit unmanaged Ressourcen direkt (
SafeHandle
und Freunde zählt nicht, wie Sie erklären Ihre eigenen Finalizer), dann nicht einen finalizer implementieren, als der GC befasst sich mit beendbar Klassen anders, auch wenn Sie später unterdrücken die finalizer. Beachten Sie auch, dass, obwohlB
nicht mit einem finalizer, es noch ruftSuppressFinalize
um korrekt mit allen Unterklassen, die einen finalizer implementieren.Wenn eine Klasse die IDisposable-Schnittstelle implementiert, es bedeutet, dass irgendwo, gibt es einige nicht verwaltete Ressourcen, die sollte man entfernen, wenn Sie fertig sind mit der Klasse. Die eigentlichen Ressourcen sind gekapselt in den Klassen; Sie müssen nicht explizit löschen. Einfach anrufen
Dispose()
oder das einwickeln der Klasseusing(...) {}
wird sicherstellen, dass alle nicht verwalteten Ressourcen sind losgeworden, als notwendig.InformationsquelleAutor der Antwort thecoop
Dem offiziellen Muster zu implementieren
IDisposable
schwer zu verstehen ist. Ich glaube, das ist besser:Einer noch besser Lösung ist, um in der Regel, dass Sie immer haben, erstellen Sie eine wrapper-Klasse für alle nicht verwalteten Ressource, die Sie behandeln müssen:
Mit
SafeHandle
und seine Derivate, diese Klassen sollten sehr selten.Das Ergebnis für Einweg-Klassen, die nicht direkt mit nicht verwalteten Ressourcen, auch in Anwesenheit von Vererbung, ist mächtig: Sie brauchen nicht besorgt zu sein mit nicht verwalteten Ressourcen mehr. Sie werden einfach zu implementieren und zu verstehen:
InformationsquelleAutor der Antwort Jordão
Beachten Sie, dass alle IDisposable-Implementierung sollten, befolgen Sie die unten aufgeführten Muster (IMHO). Ich entwickelte dieses Muster beruht auf Informationen von mehreren ausgezeichnet .NET "Götter", die .NET Framework Design Guidelines (beachten Sie, dass MSDN nicht Folgen diesem für einige Grund!). Die .NET Framework-Design-Richtlinien geschrieben wurden, von Krzysztof Cwalina (CLR Architekten zu der Zeit) und Brad Abrams (ich glaube, die CLR-Programm-Manager zu der Zeit) und Willi Wagner ([effective C#] und [More effective C#] (werfen Sie einen Blick für diese auf Amazon.com:
Beachten Sie, dass Sie sollten NIE einen Finalizer implementieren, es sei denn, Ihre Klasse direkt enthält (nicht erbt) nicht verwaltete Ressourcen. Sobald Sie einen Finalizer implementieren eine Klasse, auch wenn es nie genannt wird, es ist garantiert, um zu Leben, für eine extra-Sammlung. Es wird automatisch auf der Finalization Queue (die läuft in einem einzigen thread). Auch ein sehr wichtiger Hinweis...alle ausgeführten code in ein Finalizer (sollten Sie brauchen, zu implementieren) MUSS thread-sicher UND exception-sicher! SCHLECHTE Dinge werden passieren, sonst...(d.h. unbestimmten Verhalten und im Fall einer Ausnahme wird, ist ein schwerwiegender, nicht behebbarer application crash).
Das Muster, das ich zusammengestellt habe (und geschrieben ein code-snippet) folgt:
Hier ist der code für die Implementierung von IDisposable in einer abgeleiteten Klasse. Beachten Sie, dass Sie müssen nicht explizit Liste Vererbung von IDisposable in der definition der abgeleiteten Klasse.
Ich gebucht habe, diese Umsetzung auf meinem blog unter: Wie man Richtig Implementieren Sie das Dispose-Muster
InformationsquelleAutor der Antwort
Ich Stimme mit pm100 (und sollte ausdrücklich gesagt, das in meinem früheren post).
Sollten Sie nie implementieren IDisposable in einer Klasse, es sei denn, Sie es brauchen. Sehr spezifisch sein, gibt es etwa 5 mal, wenn Sie jemals brauchen würden/sollten implementieren IDisposable:
Ihrer Klasse enthält explizit (also nicht über eine erbschaft) verwalteten Ressourcen, die IDisposable implementieren und sollte gereinigt werden, sobald Ihre Klasse wird nicht mehr verwendet. Zum Beispiel, wenn Ihre Klasse enthält eine Instanz einer von Stream, DbCommand, DataTable, etc.
Ihre Klasse explizit enthält alle verwalteten Ressourcen, die Umsetzung einer Close () - Methode - z.B. IDataReader, IDbConnection, etc. Beachten Sie, dass einige dieser Klassen implementieren IDisposable durch Dispose() sowie Close () - Methode.
Ihrer Klasse enthält explizit eine nicht verwaltete Ressource - z.B. ein COM-Objekt, Zeiger (ja, Sie können den Zeiger verwenden, die in managed C#, aber Sie muss deklariert werden in der "unsafe" - Blöcke, etc.
Im Fall von nicht verwalteten Ressourcen, die Sie sollten auch sicherstellen, dass das aufrufen von System.- Laufzeit.InteropServices.Marschall.ReleaseComObject() auf den RCW. Obwohl der RCW ist in der Theorie ein managed-wrapper, es gibt noch Verweiszählung, die sich unter der Decke.
Wenn Ihre Klasse abonniert Ereignisse, die mit starken Referenzen. Sie müssen sich Abmelden und trennen sich selbst von den Veranstaltungen. Immer stellen Sie sicher, diese sind nicht null, bevor man versucht Abmelden/trennen!.
Ihrer Klasse enthält eine beliebige Kombination der oben...
Empfohlene alternative zum arbeiten mit COM-Objekten und zu nutzen, Marschall.ReleaseComObject() ist, das System zu nutzen.- Laufzeit.InteropServices.SafeHandle-Klasse.
Die BCL (Base Class Library Team) einen guten blog-post dazu hier http://blogs.msdn.com/bclteam/archive/2005/03/16/396900.aspx
Ein sehr wichtiger Hinweis ist, dass, wenn Sie die Arbeit mit WCF und bereinigen von Ressourcen, sollte man FAST IMMER vermeiden, die " mit " - block. Es gibt viele blog-posts gibt und einige auf der MSDN-Website über warum dies eine schlechte Idee ist. Ich habe auch geschrieben über es hier - Nicht verwenden 'mit()' mit einem WCF-proxy
InformationsquelleAutor der Antwort
Mit lambdas statt IDisposable.
Ich war nie begeistert das ganze mit/IDisposable Idee. Das problem ist, dass es erfordert, den Anrufer zu:
Meine neue bevorzugte Methode ist die Verwendung eines factory-Methode und lambda-statt
Vorstellen, ich möchte etwas tun, mit einer SqlConnection (etwas, was sein sollte, eingewickelt in ein mit). Klassisch würden Sie tun,
Neuen Weg
Im ersten Fall wird der Anrufer konnte einfach nicht verwenden Sie die using-syntax. IM zweiten Fall hat der Benutzer keine andere Wahl. Es gibt keine Methode, die erstellt wird, dass eine SqlConnection-Objekt, muss der Anrufer aufrufen DoWithConnection.
DoWithConnection sieht wie folgt aus
MakeConnection
ist jetzt privateInformationsquelleAutor der Antwort pm100
niemand beantwortet die Frage, ob sollten Sie die IDisposable implementieren, obwohl Sie brauche es nicht.
Kurze Antwort : Nein
Lange Antwort:
Dies würde es erlauben, einen Verbraucher, der Ihre Klasse für die Verwendung von 'Verwendung'. Die Frage, die ich stellen würde, ist, warum sollten Sie es tun? Die meisten devs nicht verwenden 'mit' es sei denn, Sie wissen, dass Sie es tun müssen - und wie Sie weiß. Entweder
Also durch die Implementierung von IDisposable Sie sagen devs (zumindest einige), dass diese Klasse umschließt, etwas, das losgelassen werden muss. Sie werden 'durch' - aber es gibt andere Fälle, in denen die Verwendung nicht möglich ist (der Rahmen-Objekt nicht lokal ist); und Sie müssen von vorne beginnen, sich Gedanken über die Lebensdauer der Objekte in den anderen Fällen - ich würde sorgen, für sicher. Dies ist aber nicht notwendig
Implementieren Sie Idisposable zu ermöglichen, Sie zu verwenden, aber Sie nicht verwenden, verwenden, es sei denn, Sie Ihnen sagen.
So machen es nicht,
InformationsquelleAutor der Antwort pm100
Wenn Sie mit anderen verwalteten Objekten, die mit nicht verwalteten Ressourcen, es ist nicht Ihre Verantwortung, um sicherzustellen, dass diese abgeschlossen sind. Ihre Aufgabe ist es, rufen Sie Dispose auf diese Objekte, wenn Dispose aufgerufen wird, auf Ihr Objekt, und es bleibt dort.
Wenn deine Klasse keine knappen Ressourcen, sehe ich nicht, warum Sie würden Ihre Klasse implementieren IDisposable. Sie sollten dies nur tun, wenn Sie:
Ja, der code, der verwendet, muss Ihr code die Dispose-Methode des Objekts. Und ja, der code, der verwendet Ihr Objekt verwenden können
using
als Sie gezeigt haben.(2?) Es ist wahrscheinlich, dass der WebClient verwendet nicht verwalteten Ressourcen, oder andere verwaltete Ressourcen, die IDisposable implementieren. Den genauen Grund, jedoch, ist nicht wichtig. Wichtig ist, dass es IDisposable implementiert, und so fällt es auf Sie, zu handeln nach diesem wissen, indem du das Objekt, wenn Sie fertig sind mit ihm, auch wenn es sich herausstellt, WebClient verwendet, keine anderen Ressourcen.
InformationsquelleAutor der Antwort Lasse Vågsæther Karlsen
@Icey,
Eigentlich Ihre Antwort ist leicht falsch aus 2 Gründen:
Erste,
eigentlich ist äquivalent zu:
Dies mag lächerlich klingen, da die 'neuen' Betreiber sollte nie wieder zurückkehren, "null", es sei denn, Sie haben eine OutOfMemory-exception. Aber betrachten wir die folgenden Fälle:
1. Sie rufen eine FactoryClass, gibt ein IDisposable-Ressource oder
2. Wenn Sie haben eine Art, die möglicherweise oder möglicherweise nicht Erben von IDisposable-je nach Umsetzung - daran erinnern, dass ich gesehen habe, die die IDisposable-pattern falsch implementiert viele Zeiten, zu viele Kunden, wo die Entwickler nur noch ein Dispose () - Methode ohne Erben von IDisposable (schlecht, schlecht, schlecht). Sie könnte auch den Fall der eine IDisposable-resource zurückgegeben wird von einer Eigenschaft oder Methode nicht (wieder schlecht, schlecht, schlecht - nicht " verschenken Ihre IDisposable-Ressourcen)
Wenn die 'as' operator null zurück (oder Eigenschaft oder Methode Rücksendung der Ressource), und den code in das 'mit' block schützt gegen "null", Ihr code wird nicht die Luft zu sprengen, wenn Sie versuchen, rufen Sie Dispose auf ein null-Objekt, weil der "built-in" null-check.
Der zweite Grund ist Ihre Antwort nicht korrekt ist, da der folgende vorgegeben:
Ersten, die Fertigstellung (auch als GC selbst) ist nicht-deterministisch. Die CLR bestimmt, Wann Sie rufen einen finalizer. D. H. die Entwickler/code hat keine Ahnung. Wenn die IDisposable-pattern implementiert ist korrekt (wie ich oben geschrieben habe) und GC.SuppressFinalize() aufgerufen wurde, die den Finalizer NICHT aufgerufen werden. Dies ist einer der großen Gründe, um richtig implementieren die Muster richtig. Da gibt es nur 1 Finalizer-thread pro Prozess verwaltet, unabhängig von der Anzahl der logischen Prozessoren, können Sie leicht die Leistung beeinträchtigen, indem Sie eine Sicherung oder gar das Aufhängen der Finalizer-thread vergessen zu nennen, GC.SuppressFinalize().
Habe ich geschrieben eine korrekte Implementierung der Dispose-Muster auf meinem blog: Wie man Richtig Implementieren Sie das Dispose-Muster
InformationsquelleAutor der Antwort Dave Black
Dispose-Muster:
Beispiel der Vererbung:
InformationsquelleAutor der Antwort Andrei Krasutski
entspricht
Einen finalizer aufgerufen ist, die GC zu zerstören Ihr Objekt. Dies kann zu einer ganz anderen Zeit, als wenn Sie lassen Sie Ihre Methode. Das Entsorgen von IDisposable wird sofort aufgerufen, nachdem Sie verlassen Sie den using-block. Damit das Muster wird normalerweise mit freien Ressourcen sofort, nachdem Sie nicht mehr benötigen.
InformationsquelleAutor der Antwort Daniel Fabian
1) WebClient ist eine Art verwaltet, so brauchen Sie nicht ein finalizer. Der finalizer ist erforderlich, wenn Ihre Benutzer nicht mit Dispose() des NoGateway Klasse und der native-Typ (das ist nicht die von der GC) muss gereinigt werden, nach. In diesem Fall, wenn der Benutzer nicht über Aufruf von Dispose(), die enthaltenen WebClient entsorgt werden, die vom GC direkt nach der NoGateway tut.
2) Indirekt ja, aber man sollte sich nicht darum kümmern. Ihr code korrekt ist, da steht und Sie kann nicht verhindern, dass Benutzer aus dem vergessen, Dispose() sehr leicht.
InformationsquelleAutor der Antwort Jesse C. Slicer
Muster von msdn
InformationsquelleAutor der Antwort devnull
Aus, was ich weiß, ist es dringend empfohlen, NICHT zu verwenden den Finalizer /Destruktor:
Meist ist dies aufgrund von nicht wissen, Wann oder WENN es aufgerufen wird. Die dispose-Methode ist viel besser, vor allem, wenn Sie uns mit oder entsorgen Sie direkt.
verwenden, ist gut. verwenden Sie es 🙂
InformationsquelleAutor der Antwort Nic Wise