| |

VB.NET - Ein- und UmsteigerRe: Steuerelemente disposen: Wie ist es richtig? | |  | Autor: DaveS (Moderator) | Datum: 08.07.10 15:52 |
| Hier ist ein Artikel, den ich vor vielen Jahren in einem anderen Forum gepostet habe
Erstens, Dispose() hat nichts mit Garbage Collector zu tun. Zweitens, ein Finalizer ist relativ selten notwendig.
Der Garbage Collector dagegen ist abolut notwendig und funktioniert in .Net sehr effizient. Wir waren sehr überrascht von der Geschwindigkeit unserer .Net Serveranwendungen wo wir tausende von Objekten anlegen jede Sekunde. In .Net werden Heap Objekte (d.h. Reference Types) einfach linear im vorhandenen Heapspeicher angelegt. Es wird nicht versucht ein Stück Speicher in passender Größe auszusuchen, z.B. Objekte, die nicht mehr gebraucht werden lassen einfach leeren Platz im Heap zurück. Overhead um ein Objekt anzulegen ist deswegen sehr klein. Natürlich bedeutet das, dass Speicher ziemlich schnell voll wird, und deswegen komprimiert werden muss. Und das ist Aufgabe des Garbage Collecters.
Dispose und Finalize sind nur notwendig, wenn Objekte Windows Handles verwalten, oder eingebettete Objekte haben, die solche Handles verwalten, und aus einem einfachen Grund: der Garbage Collector kann nicht wissen was ein Feld vom Typ IntPtr eigentlich darstellt. Offensichtlich müssen Klassen wie FileStream, oder eigene Klassen die aus irgendwelchen Gründen mit APIs und Handles umgehen selber dafür sorgen, dass diese Handles wieder freigegeben werden. Dafür müssen sie irgendeine Methode anbieten, wie etwa .Close() bei FileStream (wir kommen noch zu .Dispose()).
Leider kann es sein, dass ein Programm (ierer) es versäumt .Close() aufzurufen. Deshalb kann der Programmierer der Klasse dafür sorgen, dass das doch irgendwann passiert, indem er einen Finalizer programmiert. Diese Funktion wird vom Garbage Collector aufgerufen wenn das Objekt entsorgt wird, da nur der Garbage Collector genau weiss wann es so weit ist. Leider wenn nicht viel in der Anwendung passiert könnte es dauern, bis Finalizer aufregrufen wird, mittlerweile bleiben die Handles (etwa offene Dateien) gültig.
Ein Finalizer ist nicht notwendig in Klassen, die keine Windows Resourcen verwalten (etwa eine Customer Klasse), oder lediglich .Net Klassen wie FileStream benutzen. Im zweiten Fall ist aber .Dispose() notwendig (oder immerhin sehr empfehlenswert).
Da es nicht immer sinnvoll ist eine .Close() anzubieten, haben die MS Entwickler sich ein Design Pattern einfallen lassen, die allgemein für die Freigabe bestimmter Resourcen gedacht ist. Alle relevante .Net Klassen unterstützen dieses Pattern (obwohl in manchen Fällen .Dispose() protected ist, wie bei FileStream, in solchen Fällen wird .Dispose() intern von .Close() aufgerufen). Dispose, oder besser IDisposable Interface ist nicht nur ein Design Pattern, sondern wird auch vom Vb.Net Compiler unterstützt (Using Anweisung).
Dieses Pattern sieht so aus:
Basis Klasse implementiert IDisposable, und hat deswegen die Methode Dispose() (ohne Parameter).
Diese Dispose() ruft eine zweite protected Methode Dispose(bool) auf. "true" wird übergeben wenn Dipose(bool) von Dispose() aufgerufen wird. Wenn ein Finlaizer vorhanden ist, wird Dispose(bool) mit "false" vom Finalizer aufgerufen.
.Dipose(bool) sollte den Parameter prüfen, und nur wenn true eingebettete Klassen wie etwa FileStreams freigeben. Empfehlensert wenn ein Finalizer vorhanden ist, ist der Aufruf von GC.SuppressFinalize(), da nachdem .Dispose() aufgerufen wurde ist der Finalizer überflüssig. In beiden Fällen sollten irgendwelche Windows Handles freigegeben werden.
Und was bewirkt das ganze? Wenn Dispose() aufgerufen wird, wird die protected Dispose(true) aufgerufen, Unterobjekte werden auch disposed, und irgendwelche Handles freigegeben. Dann ist alles sauber. Wenn Finalizer tatsächlich läuft, weil vergessen wurde .Dispose() aufzurufen (oder vielleicht wegen eines Logikfehlers) wird Dispose(false) aufgerufen, was nur Handles freigibt. In diesem Fall sollten keine anderen Objekte angesprochen werden, da nie sicher sein kann, dass diese Objekte nicht vorher vom GC entsorgt (disposed) wurden.
Das ganze lässt sich in Basisklassen unterbringen, die nützlich sind wenn ein Objekt nicht von irgendeiner bestimmten Basisklasse abgeleitet werden soll, und IDisposable unterstützen sollte. Hier sind Beispiele für solche Basisklassen. Übrig bleibt nur .Dispose(bool) zu überladen in den abgeleiteten Klassen.
(C# Beispiele nicht vorhanden)
________
Alle Angaben ohne Gewähr. Keine Haftung für Vorschläge, Tipps oder sonstige Hilfe, falls es schiefgeht, nur Zeit verschwendet oder man sonst nicht zufrieden ist |  |
 | Sie sind nicht angemeldet! Um auf diesen Beitrag zu antworten oder neue Beiträge schreiben zu können, müssen Sie sich zunächst anmelden.
Einloggen | Neu registrieren |
  |
|
Neu! sevDTA 3.0 Pro 
SEPA mit Kontonummernprüfung
Erstellen von SEPA-Dateien mit integriertem BIC-Verzeichnis und Konto- nummern-Prüfverfahren, so dass ungültige Bankdaten bereits im Vorfeld ermittelt werden können. Weitere InfosTipp des Monats Access-Tools Vol.1 
Über 400 MByte Inhalt
Mehr als 250 Access-Beispiele, 25 Add-Ins und ActiveX-Komponenten, 16 VB-Projekt inkl. Source, mehr als 320 Tipps & Tricks für Access und VB
Nur 24,95 EURWeitere Infos
|