Dispose in C#
-
Hallo!
Für was ist eigentlich die Methode Dispose in C# gut? Diese Funktion scheint es bei fast jedem Objekt zu geben. Was macht diese und wann ruft man diese auf?
Mit bestem Dank im Voraus THE_ONE
-
Wie wär's, wenn du C#-Fragen auf dem C#-Board stellst?
-
Die gibt den Speicher und gegebenenfalls weitere Ressourcen wie Dateihandles wieder frei und aufrufen tust Du die gar nicht, das macht der Garbage Collector automatisch für Dich.
Hättest aber auch in google <Für was ist eigentlich die Methode Dispose in C# gut?> eingeben können.
-
Dispose wird auch manuell aufgerufen. In C# z.B. sehr häufig durch Verwendung des using statements oder direkt durch Dispose.
@Volkard Schiebst Du mal nach C# ?
-
@Volkard: Ein Blick ins Grundlagenbuch ist bestimmt nicht schlecht...
http://msdn.microsoft.com/en-us/library/system.idisposable.dispose(VS.71).aspx
-
volkard schrieb:
Die gibt den Speicher und gegebenenfalls weitere Ressourcen wie Dateihandles wieder frei und aufrufen tust Du die gar nicht, das macht der Garbage Collector automatisch für Dich.
NEIN!
Man sollte die tunlichst schon selbst aufrufen, und der GC wird es niemals für einen tun.Hättest aber auch in google <Für was ist eigentlich die Methode Dispose in C# gut?> eingeben können.
Das solltest du vielleicht mal tun
-
hustbaer schrieb:
volkard schrieb:
Die gibt den Speicher und gegebenenfalls weitere Ressourcen wie Dateihandles wieder frei und aufrufen tust Du die gar nicht, das macht der Garbage Collector automatisch für Dich.
NEIN!
Man sollte die tunlichst schon selbst aufrufen,Hast recht. Man sollte Dispose aufrufen, sobald man das Objekt nicht mehr braucht.
hustbaer schrieb:
und der GC wird es niemals für einen tun.
Hast unrecht. Finalize muß Dispose aufrufen oder die fraglichen Ressourcen auch freigeben.
-
Das Dispose Speicher frei gibt stimmt nicht. Dort werden unmanaged Resourcen wie z.B. die schon genannten Dateihandles freigegeben, aber niemals Speicher (also managed Speicher - das macht alleine der GC. Hat man durch Interop unmanaged Speicher allokiert kann man den schon hier freigeben).
Dispose wird nicht grundsätzlich automatisch aufgerufen, es hat sich aber neben dem using Statement was zu empfehlen ist, aber auch ein Pattern rauskristallisiert welches den Finalizer benutzt um Dispose, quasiautomatisch, aufzurufen. Wann und vor allem auch ob der Finalizer aufgerufen wird, wird aber durch den GC bestimmt und von daher ist dieses automatische Dispose aufrufen, eher ungeeignet.
-
Passt grad...
http://www.c-plusplus.net/forum/viewtopic-var-t-is-242975-and-postdays-is-0-and-postorder-is-asc-and-start-is-10.html
-
volkard schrieb:
hustbaer schrieb:
volkard schrieb:
Die gibt den Speicher und gegebenenfalls weitere Ressourcen wie Dateihandles wieder frei und aufrufen tust Du die gar nicht, das macht der Garbage Collector automatisch für Dich.
NEIN!
Man sollte die tunlichst schon selbst aufrufen,Hast recht. Man sollte Dispose aufrufen, sobald man das Objekt nicht mehr braucht.
hustbaer schrieb:
und der GC wird es niemals für einen tun.
Hast unrecht. Finalize muß Dispose aufrufen oder die fraglichen Ressourcen auch freigeben.
Nein, ich habe schon Recht.
Es war die Rede von Dispose(), und der GC wird Dispose() niemals aufrufen. Der GC ruft den Finalizer auf, und das wars.
Was der Finalizer macht, ist Sache des Finalizers.
Und den Finalizer so zu implementieren, dass er selbst IDisposable.Dispose() aufruft, ist meist ein Fehler, da man im Finalizer keine managed Referenzen mehr angreifen sollte.Vom Dispose-Pattern, welches auch eine Funktion namens "Dispose" verwendet, nur mit einem zusätzlichen bool Parameter, war hier denke ich auch nicht die Rede.
-
hustbaer schrieb:
Und den Finalizer so zu implementieren, dass er selbst IDisposable.Dispose() aufruft, ist meist ein Fehler,
Aber MS schreibt doch in http://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx
Because the Dispose method must be called explicitly, objects that implement IDisposable must also implement a finalizer to handle freeing resources when Dispose is not called.
Zufällig kannst Du rein technisch drauf Verzichten, diese Forderung zu erfüllen, gehst aber dann vom Standardverhalten weg und mußt es auffällig Dokumentieren.
hustbaer schrieb:
da man im Finalizer keine managed Referenzen mehr angreifen sollte.
Das sehe ich ein. Da scheint es logisch, den Dispose-Aufruf-Zwang einzuführen und RAII verliert den mords-Vorteil, daß man jederzeit rausreturnen oder Exceptions werfen kann, man muß nun alle Blocks mit IDisposal-Objekten per Hand schützen oder aufs Single-Entry-Singe-Exit zurückfallen.
Ist es wirklich so schlimm bestellt?
-
Magst Du das mal nach C# verschieben ?
-
Knuddlbaer schrieb:
Magst Du das mal nach C# verschieben ?
Ich kann nur von C++ nach irgenweohin wegverschieben. Hier bin ich kein Mod.
-
Dieser Thread wurde von Moderator/in Jochen Kalmbach aus dem Forum C++/CLI mit .NET in das Forum C# und .NET verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
volkard schrieb:
hustbaer schrieb:
Und den Finalizer so zu implementieren, dass er selbst IDisposable.Dispose() aufruft, ist meist ein Fehler,
Aber MS schreibt doch in http://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx
Because the Dispose method must be called explicitly, objects that implement IDisposable must also implement a finalizer to handle freeing resources when Dispose is not called.
Zufällig kannst Du rein technisch drauf Verzichten, diese Forderung zu erfüllen, gehst aber dann vom Standardverhalten weg und mußt es auffällig Dokumentieren.
Es gilt hier zu unterscheiden zwischen dem Freigeben von eigenen unmanaged Resourcen, und dem "weiterleiten" des Dispose Aufrufs, an "owned" Klassen, welche unmanaged Resourcen haben.
Wenn eine Klasse selbst keine unmanaged Resourcen besitzt, dafür aber z.B. etwas wie eine SqlConnection, dann reicht es Dispose() zu implementieren, und zwar so:public void Dispose() { m_sqlConnection.Dispose(); }
Finalizer braucht man hier keinen.
Wenn eine Klasse ausschliesslich unmanaged Resourcen hat, sagen wir einen IntPtr der ein File Handle darstellt, dann würde man es ca. so implementieren:
~MyClassName() // finalizer { Tidy(); } public void Dispose() { Tidy(); } private void Tidy() { if (m_myHandle != IntPtr.Zero) { Utility.CloseHandle(m_myHandle); m_myHandle = IntPtr.Zero; } }
Und wenn eine Klasse selbst unmanaged Resourcen UND managed Member hat welche disposed werden müssen, muss man etwas machen wie MS es mit dem "Dispose-Pattern" vorsieht. Also eine Unterscheidung ob Dispose aufgerufen wurde oder der Finalizer. Dass MS die Funktion dabei "Dispose(bool disposing)" nennt, halte ich für etwas unglücklich. Genaugenommen halte ich das ganze Dispose-Pattern für unglücklich, da es IMO ziemlich unsauber ist, eine Klasse gleichzeitig unmanaged Resourcen und "disposbare" managed Member besitzen zu lassen. Wenn man die unmanaged Resourcen in eine kleine Helper-Klasse wegkapselt, dann hat man diesen Fall nie, und braucht auch das komische Dispose-Pattern mit "Dispose(bool disposing)" nicht.
hustbaer schrieb:
da man im Finalizer keine managed Referenzen mehr angreifen sollte.
Das sehe ich ein. Da scheint es logisch, den Dispose-Aufruf-Zwang einzuführen und RAII verliert den mords-Vorteil, daß man jederzeit rausreturnen oder Exceptions werfen kann, man muß nun alle Blocks mit IDisposal-Objekten per Hand schützen oder aufs Single-Entry-Singe-Exit zurückfallen.
Ist es wirklich so schlimm bestellt?Ja, klar. RAII kann man in GC Sprachen zwar noch machen, aber RRID geht nichtmehr. Das betrifft nicht nur C#, sondern eigentlich alle Sprachen, die keine deterministische Finalisierung unterstützen. Also so ziemlich alles was GC verwendet.
In C# gibt es aber netterweise das Keyword "using":void Test() { using (SqlConnection con = GetMeMySqlConnection()) { con.Open(); using (SqlCommand cmd = con.CreateCommand()) { // ... } // hier automatisch cmd.Dispose(), auch bei Exceptions oder return; im Block } // hier automatisch con.Dispose() }
In Java ist das alles wesentlich lästiger. Dort gibt's kein standardisiertes Interface ala IDisposable zum Freigeben von unmanaged Resourcen, und dadurch auch kein Sprachkonstrukt ala "using". Es gibt IIRC nichtmal einen Standard für den Namen der Funktion die die Resourcen freigibt (meistens Close(), aber wenn ich mich nicht irre gibt's ein paar Klassen wo die Funktion anders heisst).
Da muss man also wirklich immer mit try-finally arbeiten.
-
Kurze Frage, welche hier gerade reinpasst:
Sollte man eigentlich immerDispose
aufrufen, wenn eine entsprechende Methode angeboten wird und man das Objekt nicht mehr benötigt? Also zum Beispiel beiSystem.Windows.Forms
Klassen. Und wird dannDispose
für die Childcontrols automatisch auch aufgerufen?Grüssli
-
Also ich hab die Erfahrung gemacht, das es sich immer dann wenn eine Klasse das IDisposable implementiert, man diese auch ruhig mit dem Using-Idiom benutzen sollte, dann brauch man zum einen das Dispose nicht explizit aufrufen, kann es somit auch nicht vergessen und es ist ebend Exceptionsicher usw.
Wie das mit den Childcontrols ist weiß ich nicht, aber ich kann dir den .net Reflector empfehlen, der gewährt dir einen einblick in die Implementation der ganzen .Net Klassen, da kannst du ja bei Interesse einfach nach schauen.
-
Dravere schrieb:
Kurze Frage, welche hier gerade reinpasst:
Sollte man eigentlich immerDispose
aufrufenKommt auf den Kontext an. Einmal habe ich diverse Spalten in einem Datagridview selber gemalt um das Control nicht zu fett werden zu lassen (Fragt jetzt nicht wieso dann nicht den virtual mode nehmen). Dort habe ich immer dieselben 10 Stifte und 8 Pinsel benötigt und sie deshalb in einer Factory bereitgestellt welche immer dieselben Objekte gab. Preiswerter als jedes Dispsing. Kann man aber nur machen wenn die Objektzahl klein und vorherbestimmt ist. Den SqlCommand in hustbear's Beispiel würde ich auch nicht unbedingt in einem using-Block packen bloß damit sich das Teil am Metacache abmeldet ... . Die SqlConnection ist natürlich kein Thema.
-
Grundsätzlich gehört alles disposed was IDisposable implementiert.
Was Child-Controls angeht: die Form erledigt das. Der Forms Editor generiert z.B. auch den nötigen Code, um "Components" (wie z.B. Timer) beim Schliessen der Form zu disposen.
Wenn man Components in selbstgeschriebenem Code irgendwo anlegt, muss man aber auch selbst dafür sorgen, dass diese disposed werden. Wenn die Component in einer über den Forms Editor erstellten Form lebt, dann sollte es reichen, die Component in die "components" Collection reinzustecken.Oder kurz: man sollte halt einfach wissen was wo von wem automatisch disposed wird, und was man selbst entsorgen muss.
Auch gibt es einige Dinge die man tunlichst nicht disposen sollte. z.B. WindowsIdentity Instanzen. Angenommen man hat eine WindowsIdentity Instanz, und diese gerade mit Impersonate() "aktiviert". Wenn man nun mit dieser "aktivierten WindowsIdentity" z.B. eine SqlConnection aufbaut, und danach die "WindowsIdentity" disposed, dann wird früher oder später in irgendeinem Worker-Thread des Frameworks eine ObjectDisposedException fliegen.
Ist IMO ein Fehler im Framework. Vor allem weil es nicht nur SqlConnections betrifft, sondern z.B. alles was Timer erzeugt. Und weil man nicht wirklich wissen kann, welche Funktion evtl. einen Timer erzeugen könnte. Und weil sich das auch von Version zu Version ändern könnte.
Ergo: WindowsIdentity Instanzen die jemals "aktiviert" waren sollten nie disposed werden. Ist zwar eigentlich "pfui", aber die einzige (mir bekannte) Möglichkeit, das hier beschriebene Problem zu vermeiden.Wer näheres wissen will: mit Google gibt es einige Artikel zu dem Thema zu finden.
-
Schöner ausführlicher Artikel zum Thema:
http://ondotnet.com/pub/a/dotnet/2002/02/11/csharp_traps.html
Hier nochmal ein Beispiel von mir:
public class MyClass : IDisposable { private bool _bDisposed = false; // Konstruktor public MyClass() { } // Destruktor, Ersatzmakro für // protected override void Finalize() ~MyClass() { this.Dispose(false); } // öffentliche Dispose-Methode zum Aufräumen public void Dispose() { this.Dispose(true); } // interne Dispose-Methode private void Dispose(bool bDisposing) { if (!_bDisposed) { if (bDisposing) { // hier managed Resourcen freigeben } } _bDisposed = true; } }