Laden...

Wann sollte eine Klasse von IDisposable erben?

Letzter Beitrag vor 18 Jahren 15 Posts 8.255 Views
Wann sollte eine Klasse von IDisposable erben?

Hallo zusammen,

-Wenn ich eine eigene Klasse erzeuge, wann solte diese von IDisposable
erben? oder anderst, welche Aufreumarbeiten benötigen ein Dispose?

-Wenn ich von IDisposable erbe, muß ich Dispose implementieren.
Die Frage ist jetzt, werden alle Aufreumarbeiten ausschließlich in Dispose
eingebaut und nicht im Destruktor? Ist dem nach der Destruktor
nur dan zu verwenden wenn die Klasse nicht von IDisposable erbt?

Gruß Kostas

Dispose

Immer dann, wenn Du in einer Klasse Instanzmember verwendest, die auch IDisposable implementieren. Und außerdem immer dann, wenn Du Verweise auf unmanaged Code (COM, Win32) hältst (In der Dispose-Methode ReleaseComObject für jeden COM-Verweis aufrufen, das ist sehr wichtig!)

Darüber hinaus sollte IDisposable immer dann implementiert werden, wenn eine Ressourcen bindet. IDisposeable gibt dem Anwender der Klasse die Möglichkeit gebundene Ressourcen (z.B offene Dateien etc.) zu einem definierten Zeitpunkt freizugeben. Das ist sehr wichtig, da der Garbage Collector macht was er will (Kommt er heut nicht, kommt er vielleicht morgen).

Dieses Forum ist unglaublich wertvoll. (Werde mir etwas einfallen lassen)

ich habe vor mir vier Bücher, alle beschreiben wie Dispose angewandt
wird von der Syntax her, aber keines wann und warum. Die gehen einfach
davon aus dass das eh jeder weis.

Naja, jetzt gehöre ich auch zu denen.

Herzlichen Dank Rainbird

Bei der späteren Anwendung kann ich dir das using Statment empfehlen.

Damit brauchst du nicht selbst die Dispose/Close Methode aufzurufen um Speicher freizugeben, sondern dies erledigt das using Statment.

Kleines Beispiel (Vb.NET)


Using resource As New resourceType
' Insert code to work with resource.
End Using

' THE FOLLOWING TRY CONSTRUCTION IS EQUIVALENT TO THE USING BLOCK
Dim resource As New resourceType
Try
' Insert code to work with resource.
Catch ex As Exception
' Insert code to process exception.
Finally
' Insert code to do additional processing before disposing of resource.
resource.Dispose()
End Try

Vorteil davon ist, das du es nicht vergessen kannst das Objekt freizugeben und auch bei einer Exception (ausser StackOverflowException), wird das Objekt freigeben!

Gruss plongo


Woher soll ich wissen, was ich denke, bevor ich höre, was ich sage!
Kurzum: Läufer sind gesünder, "gescheiter" und glücklicher als Nichtläufer.
www.andreas-nicole.de

Hallo Kostas,

zum Thema IDisponsable und Destruktoren.

Ich habe es mir angewöhnt allen Klasen, die IDisposable implementieren eine Close() funktion zu spendieren.
Dise funktion sollte nur dann was tun, wenn der interne status auf open ist (alse ein aufruf Close auf ein bereits geschlossenens object sollte keine Exception schmeissen. eher ein false zurückliefern)

Die wird dann von der IDisposable.Dispose methode aufgerufen.
In dieser Methode wird dann auch der Destructor Disabled (GC.SupressFinalize).

Im Destruktor wird dann Close() aufgerufen um die resourcen wenigstens dann freizugeben, wenn der GC das objekt Finalized.
Damit kann man sicher sein, das das Objekt - irgendwann zumindest - seine Rresoucen freigibt.

Bsp. (gaaaanz grob):

public class ResourceHolder : IDisposable
{
	private Handle m_SomeWin32Handle;
	public ResourceHolder()
	{	
		// criticla resource! Must be closed!
		this.m_SomeWin32Handle = AquireHandle();
	}
	
	~ResourceHolder()
	{
		// last chance close
		this.Close();
	}
	
	// Close the handle if it is openend
	// returns false if the handle was already closed
	public bool Close()
	{
		if (m_SomeWin32Handle == null)
			return false;
		this.m_SomeWin32Handle.Close();
		this.m_SomeWin32Handle = null;
		return true;
	}
	
	
	public void Dispose()
	{
		// close Handle;
		this.Close();
		
		// make sure Finalizer will not be called...
		GC.SupressFinalize(this);
	}

}

Hallo cadi,

warum wird beim Dispose SupressFinalize finalize aufgerufen, beim Close aber nicht? Das sollte auch beim Close (direkt oder indirekt erfolgen).

Außerdem gibt es ein von Microsoft vorgeschlageses Muster zum Implementieren von Dispose. Mein Vorschlag, der diesem Muster folgt, steht in Dispose implementieren und verwenden (IDisposable).

herbivore

@herbivore

das kein GC.SupressFinalize rührt daher, das es ja evtl. auch ein (Re-)Open geben könnte. (ok, mann könnte im open auch wieder den Finalizer aktivieren).

Das Pattern von MS / dir ist letztlich doch das selbe in grün, oder?

Das wichtige ist ja nur, das auch bei "falscher" anwendung der klasse (d.h. fehlender Aufruf von Dispose oder ohne using) die resourcen freigegeben werden, oder?

btw:

~MyClass ()
{
   Dispose (false);
}

warum werden im Destruktor die "Unverwalteten Ressourcen" NICHT freigegeben?

Hallo cadi,

Das Pattern von MS / dir ist letztlich doch das selbe in grün, oder?

ja, eben, das ist ja gerade der Grund den Pattern von MS zu benutzen. Von Standard abzuweichen, um dasselbe in grün zu machen, ist eben m.E. nicht sinnvoll.

warum werden im Destruktor die "Unverwalteten Ressourcen" NICHT freigegeben?

Sorry, mein Fehler. Muss natürlich genau umgekehrt sein. Ich habe es in dem anderen Thread korrigiert.

herbivore

@herbivore

Dann ist ja alles klar.
Werde nur noch das MS Muster nutzen (tu ich eh, bei allen klassen, die von einem MS-Disposable abgeleitet sind. Das andere Muster hatt ich mir schon früh angewöhnt... (tja, man kann ja nicht alles wissen... und sowas schleift sich halt ein...)

Original von Kostas
ich habe vor mir vier Bücher, alle beschreiben wie Dispose angewandt
wird von der Syntax her, aber keines wann und warum. Die gehen einfach
davon aus dass das eh jeder weis.

Ich glaube manchmal, dass einige Buchautoren selber manches nicht wissen und deshalb das eine oder andere aus der Online-Hilfe bzw. MSDN Libarary mehr oder weniger 1:1 übernehmen 😉. Mir ist das erst kürzlich bei verschiedener Literatur zum Thema XSD Validierung aufgefallen. Alle hatten den selben Beispielcode.

Hallo zusammen,

hab noch eine Frage zu dem Thema.
Eine Klasse beinhaltet ein paar Felder, einen Timer und stellt ein Event zur
Verfügung. Wenn der Timer abgelaufen ist, gibts eben ein event.

In der Winform wurde ein private Dictionary angelegt
welches eine paar diese Objekte hält.
Jeder event der Objekte wurde auch registriert und gibt auf eine TextBox
statusmeldungen von jedem einzelnen Objekt aus.

Die Frage ist nun, was sollte ich bei FormClosing machen?
Sollte ich das Dictionary durchgehen und die events deregistrieren
und den timer anhalten? Sicherlich wird es nicht schaden, aber
würde sich das irgend wie auswirken wenn ich es nicht mache?

Gruß Kostas

Hallo Kostas,

im FormClosing solltest du das keinesfalls machen, sondern wenn dann im Dispose (bool) des Forms. Der reinen Lehre nach solltest du es (da) auch machen. Aber in der Praxis wird es bei den genannten Objekten kaum einen Unterschied machen.

herbivore

Hallo herbivore,

soeben wollte ich Deins umsetzen, hab aber gesehen das Form1.Dispose
im Eigenschaften Explorer nicht angezeigt wird. Dispose ist im File
Form1.Designer.cs enthalten. Da sollte man ja nicht hineingreifen.
Wie bekomme ich bitte Dispose in Form1.cs durch einfaches kopieren
von Form1.Designer.cs?

Gruß Kostas

Hallo Kostas,

ich benutze den Designer nicht. Daher stellen sich solche nervigen Fragen für mich nicht. Deshalb kann ich hier aber leider auch nicht helfen.

herbivore

Designer

Du kannst ohne Probleme dort eingreifen. Allerdings solltest Du den Code, den der Designer erstellt hat, nicht verändern. Du kannst aber neuen Code hinzufügen.