Implementierung von Dispose/IDisposable
-
Hallo zusammen,
ich habe mir gerde das hier angeschaut:
http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspxMir fällt auf, dass sowohl in der Basisklasse, als auch in der abgeleiteten klasse jeweils eine membervariable
private bool disposed = false;
existiert.
Kann man das nicht auch so implementieren, dass man das nur einmal (in der basisklasse hat)?
Würde dann ungefähr so aussehen:
public class Base: IDisposable { private bool disposed = false; //Implement IDisposable. public void Dispose() { if(!disposed) { Dispose(true); GC.SuppressFinalize(this); } } protected virtual void Dispose(bool disposing) { //dispose something disposed = true; } ~Base() { // Simply call Dispose(false). Dispose (false); } } public class Derived: Base { //keine disposed membervariable protected override void Dispose(bool disposing) { if (disposing) { // Release managed resources. } // Release unmanaged resources. // Set large fields to null. // Call Dispose on your base class. } base.Dispose(disposing); } // The derived class does not have a Finalize method // or a Dispose method without parameters because it inherits // them from the base class. }
Was spricht dagegen?
Edit:
Und noch eine Frage:
Werden alle Destruktoren beim beenden des Programms aufgerufen?
Ich habe gelesen, dass das im Normalfall nicht der Fall ist, habe aber auch schon wiedersprüchliches gehört.
-
Deine Idee müsste funktionieren.
Der Finalizer (in C# wird der Destruktor genannt) wird aufgerufen sobald der Garbage Collector es für sinnvoll und möglich erachtet. Aber spätestens bei regulärer Beendigung der Applikation werden alle Finalizer aufgerufen.
Die Finalizer werden vom GC sogar extra beachtet.
MSDN schrieb:
The garbage collector keeps track of objects that have Finalize methods, using an internal structure called the finalization queue. Each time your application creates an object that has a Finalize method, the garbage collector places an entry in the finalization queue that points to that object. The finalization queue contains entries for all the objects in the managed heap that need to have their finalization code called before the garbage collector can reclaim their memory.
-
danke für die antwort.
ich überlege mir jetzt, ob ich das mit dem IDisposable erstmal weglasse und nur destruktoren verwende, wenn diese eh spätestens beim beenden aufgerufen werden.
Aber microsoft/msdn betont immer wieder, dass destruktoren schlecht für die performance sind. so ganz kann ich das nicht nachvollziehen...
-
Mach das Disposable am besten doch wieder, dann werden Resourcen auch früher freigegeben.
zb wenn du ein Objekt in einem using erstellst, dann wird das Dispose direkt aufgerufen sobald der Scope verlassen wird. Wenn du dich auf den Finalizer verlässt kann die Resource noch eine ganze weile im Speicher rum liegen bis es freigegeben wird da der Garbage Collector nach eigenen ermessen los legt. Resourcen sollten aber freigegeben werden sobald man sie nicht mehr benötigt.Ich konstruiere mal ein Beispiel, du hast ein "MyReader" Objekt der eine Handle zu einem Bild auf macht.
foreach (var folder in folders) { object folderImage = null; using (var reader = new MyReader("theImage.png") folderImage = reader.GetImage(); myList.Add(new Folder(folder, folderImage); }
Stell dir vor das "MyReader" IDisposable nicht implementiert und die Datei "theImage" liest, da kann es passieren das es dir um die Ohren fliegt da der Garbage Collector erst los läuft sobald er es will.
Falls es nicht knallt hast du dann X Handles offen, und kannst dann Probleme bekommen.
Wenn "MyReader" aber IDisposable implementiert, wird es jedes mal aufgeräumt sobald der using Scope verlassen wird, d.h. du hast da immer nur ein handle zur selben Zeit offen und es kommt nicht zu unerwarteten Fehlern wegen nicht aufgeräumten Resourcen.Man ruft das IDisposable nur als Sicherheit im Finalizer auf, falls das Dispose() vergessen wurde. Also sobald du mit Resourcen Arbeitest die aufgeräumt werden müssen, solltest du das IDisposable implementieren.
//Dazu
Aber microsoft/msdn betont immer wieder, dass destruktoren schlecht für die performance sind. so ganz kann ich das nicht nachvollziehen
Microsoft sagt "Implementing Finalize methods or destructors can have a negative impact on performance" - also es kann aber muss nicht.
Es wird damit begründet das der Garbage Cllector das Objekt dann zwei mal ansteuert, einmal um den Finalizer auf zu rufen und dann nochmal um es aus dem Speicher zu schmeißen. Das kann Performance Probleme geben wenn du sehr viele solcher Objekt hast.