Re: Dispose, Finalize

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance



Hallo Karsten,

Karsten Sosna <k.sosna-NOSPAM@xxxxxxxxxxx> schrieb ...
>> Wenn in dem Beispiel unten Dispose nicht aufgerufen wird, dann wird
>> auch kein cls1.Dispose aufgerufen und die in Class1 gebundenen
>> Ressourcen werden ggf. nicht freigegeben.
>
> Private G As Graphics
>
> Private Sub Form1_Load(ByVal sender As Object, ByVal e As
> System.EventArgs) Handles MyBase.Load
> G = Me.CreateGraphics
> End Sub

Da ich davon ausgehe, das "Test" der Prototyp von irgendwas
sein soll: Abseits von der Dispose Diskussion funktioniert
das nicht.

Denn ein Graphics hängt intern immer noch an einem DeviceContext,
der wiederum an einem internen Fenster Handle hängt ->
Control.CreateGraphics ruft hier GdipCreateFromHWND auf.
(der Name sagt eigentlich schon alles).

Das Fenster Handle wiederum wird unter unterschiedlichsten Bedingungen
von den Windows Forms automatisch neuerstellt wird, siehe auch
Control.RecreateHandle.
Und damit wird auch Graphics (und Hdc) ungültig.

Und deswegen wird seit Urzeiten (Windows 1.X) ein HDC wie
heute ein Graphics nie auf längere Zeit aufbewahrt, sondern
nur für eine ununterbrochene Aktion genutzt.

> Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
> System.EventArgs) Handles Button1.Click
> G.Clear(Color.DarkGray)
> Dim t As New Test(G)

und deswegen sollte da eher stehen
Dim t As new Test(Me.CreateGraphics)

> 't.Dispose
> End Sub

> Public Class Test
> Implements IDisposable
>
> Private _G As Graphics
> Private _hDC As IntPtr
> Private IsDisposed As Boolean
>
> Public Sub New(ByVal G As Graphics)
> _G = G
> _hDC = G.GetHdc
> End Sub

und auf diese GetHdc Zwischenspeicherei wäre somit zu verzichten,
sondern die enthaltenen Methoden, das tun lassen.
Womit der Grund für IDisposable entfallen würde und eher
schädlich ist:
Da hier Graphics kein Disposable (Objekt) für den HDC kennt -
nach oben sollte der Grund ansatzweise klar sein - sollte
man das nicht durch die Hintertür tun.

Der Rest abseits von Deiner konkreten Implementation.

> Public Sub Dispose() Implements System.IDisposable.Dispose
> _G.ReleaseHdc(_hDC)
> IsDisposed = True

Wenn dies in sinnvollerem Kontext passieren würde, käme hier noch ein:
GC.SuppressFinalize(Me)

hin, so dass die Finalize Methode nicht aufgerufen wird, da der
Grund dafür bereits entfallen ist.
Und somit das Objekt direkt eingesammelt werden kann, wenn es
den Gültigkeitsbereich (oben Button1_Click) verlassen hat.

> Protected Overrides Sub Finalize()


Wo IDisposable ist zunächst rein freiwillig ist, interessiert
sich der Garbage Collector sehr wohl für die Finalize Methode.
Wenn ein Finalizer existiert wandert ein Objekt zunächst bei
der Garbace Collection in einen Finalisierung Stapel.
Es wäre keine sofortige Entsorgung möglich.

> If Not IsDisposed Then
> Call Dispose()
> End If

Und damit das auch in Vererbungshierarchien funktioniert, wird bei
Public Klassen üblicherweise ein Muster mit einem
Protected Overloads Overridable Sub Dispose(disposing As Boolean)
verwendet wie es gezeigt wird in
http://msdn.microsoft.com/library/en-us/cpgenref/html/cpconFinalizeDispose.asp?frame=true

Und siehe auch weitere Antwort in diesem Thread.

Gruss
Elmar

.


Quantcast