Die Umsetzung IDisposable auf einer versiegelten Klasse
Frage
Ich glaube nicht, diese Frage vor gefragt wurde. Ich bin ein wenig verwirrt über die beste Art und Weise IDisposable
auf einer versiegelte Klasse spezifisch, eine versiegelte Klasse zu implementieren, die nicht von einer Basisklasse erbt. (Das heißt, eine „reine versiegelte Klasse“, die mein gemacht ist bis term.)
Vielleicht mit mir in einige von Ihnen zustimmen, dass die Richtlinien für IDisposable
Umsetzung sehr verwirrend sind. Das heißt, ich will wissen, dass die Art, wie ich die Absicht IDisposable
zu implementieren, ist ausreichend und sicher.
Ich bin etwas P tun / Invoke Code, der eine IntPtr
durch Marshal.AllocHGlobal
zuordnet und natürlich möchte ich von dem nicht verwalteten Speicher sauber entsorgen die ich angelegt habe. Also ich denke an so etwas wie diese
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public sealed class MemBlock : IDisposable
{
IntPtr ptr;
int length;
MemBlock(int size)
{
ptr = Marshal.AllocHGlobal(size);
length = size;
}
public void Dispose()
{
if (ptr != IntPtr.Zero)
{
Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
GC.SuppressFinalize(this);
}
}
~MemBlock()
{
Dispose();
}
}
Ich gehe davon aus, dass, weil MemBlock
vollständig abgedichtet ist und nie von einer anderen Klasse abgeleitet wird, dass ein virtual protected Dispose(bool disposing)
Umsetzung nicht notwendig ist.
Auch die Finalizerthread unbedingt notwendig? Alle Gedanken begrüßen zu können.
Lösung
Die Finalizerthread ist als Ausweichmechanismus notwendig, um schließlich frei von nicht verwalteten Ressourcen, wenn Sie vergessen haben, Dispose
zu nennen.
Nein, Sie sollten keine virtual
Methode in einer sealed
Klasse deklarieren. Es wäre überhaupt nicht kompilieren. Auch ist es nicht zu empfehlen, um neue protected
Mitglieder in sealed
Klassen zu deklarieren.
Andere Tipps
Ein kleiner Zusatz; in der Allgemein Fall ist ein gemeinsames Muster eine Dispose(bool disposing)
Methode zu haben, so dass Sie wissen, ob Sie in Dispose
sind (wo mehr Dinge vorhanden sind) gegen den Rest der Finalizerthread (wo man nicht wirklich berühren sollte andere verbunden verwaltete Objekte).
Zum Beispiel:
public void Dispose() { Dispose(true); }
~MemBlock() { Dispose(false); }
void Dispose(bool disposing) { // would be protected virtual if not sealed
if(disposing) { // only run this logic when Dispose is called
GC.SuppressFinalize(this);
// and anything else that touches managed objects
}
if (ptr != IntPtr.Zero) {
Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
}
}
Für versiegelte Klassen, dieses Muster braucht nicht gefolgt werden, dh Sie sollten einfach implementieren Ihre Finalizer und Entsorgen mit den einfachen Methoden (d.h. ~ T () (Finalisieren) und Dispose () in C #). Bei dem letzteren Weg wählen, Ihre Code sollte noch an die haften Richtlinien unten in Bezug auf Umsetzung der Fertigstellung und entsorgen Logik.
Also ja, sollten Sie gut sein.
Sie tun müssen, die Finalizerthread als Mehrdad erwähnt. Wenn Sie es vermeiden wollen, könnte nehmen Sie einen Blick auf Safehandle . Ich habe nicht genug Erfahrung mit P / Invoke die korrekten Verwendung vorzuschlagen.
Sie können keine virtuellen Methoden in einer versiegelten Klasse deklarieren. Auch geschützte Mitglieder in einer versiegelten Klasse deklarieren gibt Ihnen eine Compiler-Warnung. So haben Sie es richtig umgesetzt. Der Aufruf GC.SuppressFinalize (this) aus dem Finalizerthread ist aus offensichtlichen Gründen nicht notwendig, aber es kann nicht schaden.
Mit einem Finalizerthread wesentlich ist, wenn sie mit nicht verwalteten Ressourcen zu tun, weil sie nicht automatisch befreit sind, haben Sie es in der Finalizerthread zu tun mit automatisch aufgerufen wird, nachdem das Objekt Müll gesammelt wurde.