Aufruf von base.Dispose() wird automatisch von abgeleiteten Klassen
Bearbeiten - Neue Frage
Ok können formulieren Sie die Frage mehr allgemein.
Mit der spiegelung, gibt es eine Möglichkeit, dynamisch aufrufen zur Laufzeit wird eine Basis-Methode der Klasse, die Sie können überschreiben werden. Sie können nicht mit dem 'base' - Schlüsselwort zur compile-Zeit, da Sie sich nicht sicher sein kann, dass es existiert. Zur Laufzeit möchte ich die Liste meiner Vorfahren Methoden, und nennen Sie die Vorfahr-Methoden.
Versuchte ich mit GetMethods() und solche aber alle, die Sie zurück sind "Zeiger", um die abgeleitete Implementierung der Methode. Nicht eine Umsetzung auf eine Basisklasse.
Hintergrund
Entwickeln wir ein system, in C# 3.0 mit einer relativ großen Klasse Hierarchie. Einige dieser Klassen, überall in der Hierarchie, Ressourcen haben, müssen
entsorgt, diejenigen Umsetzung der IDisposable - Schnittstelle.
Das Problem
Nun, zur Erleichterung der Wartung und refactoring von code würde ich gerne einen Weg finden, für Klassen, die IDisposable implementieren,
auf "automatisch" nennen Basis.Dispose(bDisposing), wenn irgendwelche Vorfahren auch IDisposable implementiert. Wenn auf diesem Weg einige Klasse höher in der Hierarchie beginnt die Umsetzung
oder hält der IDisposable implementiert, wird automatisch erledigt.
Das Problem ist zwei Falten.
- Zunächst, herauszufinden, ob irgendwelche Vorfahren IDisposable implementiert.
- Zweiten Aufruf base.Dispose(bDisposing) bedingt.
Den ersten Teil, zu finden über die Vorfahren der IDisposable implementiert, die ich in der Lage gewesen zu bewältigen.
Der zweite Teil ist der "tricky". Trotz all meiner
die Bemühungen, ich habe nicht in der Lage zu nennen base.Dispose(bDisposing) von einer abgeleiteten Klasse. Alle meine versuche fehlgeschlagen. Entweder Sie verursachten
Kompilierung Fehler oder rief die falschen Dispose () - Methode, die meisten abgeleitet, um die Schleife für immer.
Das Hauptproblem ist, dass Sie kann nicht beziehen sich eigentlich auf Basis.Dispose() direkt in Ihrem code, wenn es keine solche Sache wie ein
Vorfahren der Umsetzung (daran erinnert werden, dass es vielleicht keine Vorfahren noch der IDisposable implementiert, aber ich will den abgeleiteten code, um bereit zu sein, Wann und ob eine solche
eine Sache in der Zukunft passiert). Lassen Sie uns mit der Reflexion Mechanismen, aber ich habe nicht gefunden, eine richtige Weg, es zu tun. Unser code ist ziemlich gefüllt mit
erweiterte Reflexions-Techniken, und ich denke, dass ich nicht verpassen nichts offensichtlich dort.
Meine Lösung
Mein bestes war noch einige bedingte code Verwendung im code auskommentiert. Ändern der IDisposable-Hierarchie würden die entweder brechen die build -
(wenn keine IDisposable Vorfahren vorhanden) oder eine exception werfen (wenn es IDisposable Vorfahren, sondern base.Entsorgen ist nicht genannt).
Hier ist etwas code, den ich Beitrag bin, um zu zeigen, was meine Dispose(bDisposing) - Methode aussieht. Ich Stelle in diesem code am Ende der Dispose () -
Methoden in der gesamten Hierarchie. Alle neuen Klassen sind erstellt aus Vorlagen, die auch diesen code.
public class MyOtherClassBase
{
//...
}
public class MyDerivedClass : MyOtherClassBase, ICalibrable
{
private bool m_bDisposed = false;
~MyDerivedClass()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool bDisposing)
{
if (!m_bDisposed) {
if (bDisposing) {
//Dispose managed resources
}
//Dispose unmanaged resources
}
m_bDisposed = true;
Type baseType = typeof(MyDerivedClass).BaseType;
if (baseType != null) {
if (baseType.GetInterface("IDisposable") != null) {
//If you have no ancestors implementing base.Dispose(...), comment
//the following line AND uncomment the throw.
//
//This way, if any of your ancestors decide one day to implement
//IDisposable you will know about it right away and proceed to
//uncomment the base.Dispose(...) in addition to commenting the throw.
//base.Dispose(bDisposing);
throw new ApplicationException("Ancestor base.Dispose(...) not called - "
+ baseType.ToString());
}
}
}
}
So ist, bin ich Fragen, ist es ein Weg, um call-Basis.Dispose() automatisch/bedingt statt?
Mehr Hintergrund
Es ist ein weiterer Mechanismus in der Anwendung, in der alle Objekte erfasst werden, die mit einer main-Klasse. Die Klasse prüft, ob Sie implementieren IDisposable.
Wenn ja, sind Sie ordnungsgemäß zu entsorgen, die von der Anwendung. Dadurch wird vermieden, dass der code durch die Verwendung der Klassen zu beschäftigen
der Aufruf von Dispose() aus ganz von selbst. So, zusätzlich IDisposable zu einer Klasse, die keine Vorfahren Geschichte der IDisposable-funktioniert immer noch perfekt.
InformationsquelleAutor Philibert Perusse | 2008-09-16
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die standard-Muster ist für Ihre Basis-Klasse implementiert IDisposable und die nicht-virtuellen Dispose () - Methode und implementieren einer virtuellen Dispose(bool) - Methode, die die Klassen, die Einweg-Ressourcen überschreiben muss. Sie sollten immer rufen Sie Ihre Basis von Dispose(bool) - Methode, die Kette bis zu der obersten Klasse in der Hierarchie schließlich. Nur diejenigen Klassen, die sich überschreiben, es wird aufgerufen werden, damit die Kette ist in der Regel Recht kurz.
Finalizer, geschrieben ~Klasse in C# nicht. Sehr wenige Klassen, die einen brauchen, und es ist sehr leicht versehentlich halten große Objekt-Graphen um, weil der Finalizer erforderlich, dass mindestens zwei Kollektionen, bevor der Speicher freigegeben wird. Auf der ersten Kollektion, nachdem das Objekt nicht mehr referenziert wird, es ist auf eine Warteschlange von Finalizer ausgeführt werden. Diese laufen auf einem separaten, dedizierten thread, die läuft nur Finalizer (wenn es blockiert wird, nicht mehr Finalizer ausgeführt und der Speicherverbrauch explodiert). Sobald der finalizer ausgeführt wurde, wird die nächste Sammlung, sammelt die entsprechende generation wird frei das Objekt-und nichts anderes war es die Referenzierung, die nicht anderweitig verwiesen wird. Leider, denn es überlebt die erste Kollektion, wird es in der älteren generation, die gesammelt, weniger Häufig. Aus diesem Grund sollten Sie Entsorgen Sie früh und oft.
In der Regel, sollten Sie implementieren eine kleine Ressource wrapper-Klasse, die nur verwaltet die Ressource Lebenszeit und einen finalizer implementieren, die für diese Klasse, plus IDisposable. Der Benutzer der Klasse soll dann rufen Sie Dispose auf, wenn es entsorgt wird. Es sollte nicht sein, ein back-link an den Benutzer. So, nur die Sache, eigentlich braucht Abschluss landet auf der finalization queue.
Wenn Sie gehen zu müssen, wie Sie überall in der Hierarchie der Basis-Klasse implementiert IDisposable implementieren sollte der finalizer und Aufruf von Dispose(bool) auf und übergeben Sie false als parameter.
WARNUNG für Windows-Mobile-Entwickler (VS2005 und 2008 .NET Compact Framework 2.0 und 3.5): viele nicht-Steuerelemente, die Sie drop in Ihre designer-Oberfläche, z.B. Menüleisten, Timer, HardwareButtons, abgeleitet aus dem System.ComponentModel.Komponente, die einen finalizer implementiert. Für desktop-Projekte, Visual Studio fügt die Komponenten zu einem System.ComponentModel.Container mit dem Namen
components
, die es generiert code, der zu Entsorgen ist, wenn die form Entsorgt wird - Sie Verfügt über alle Komponenten, die Hinzugefügt wurden. Für die mobile-Projekten, den code zu Entsorgencomponents
generiert wird, aber das fallenlassen einer Komponente auf der Oberfläche generiert nicht den code, fügen Sie es zucomponents
. Sie haben, dies selbst zu tun, die in Ihrem Konstruktor nach dem Aufruf von InitializeComponent.Es gibt keine solche Sache wie ein Standard-finalizer. Wenn Sie nicht zu erstellen, ist es nicht vorhanden und kein Abschluss erfolgen wird.
Klassen, die IDisposable implementieren in der Regel sollte einen finalizer implementieren zusammen mit den standard-Einweg-Muster beinhaltet einen Aufruf von GC.SuppressFinalize(this) in "public Dispose()" zu vermeiden, die Kosten für einen finalizer, wenn der Anrufer verfügt über richtig.
Wenn ein Objekt einen finalizer implementiert, weder er,
Viel
Dispose()
Methoden existieren nur anrufen member-Variablen'Dispose()
Methoden. Solche Klassen sollten nicht einen finalizer implementieren; nur Klassen, die direkt eigenen nicht verwaltete Ressourcen sollten immer Finalizer implementieren. Ich denke, die besteDispose()
Muster findet sich inWindows.Forms
:protected virtual Dispose(bool disposing) { if (disposing) {member.Dispose();} idempotentUnmanagedResourceFree(); } public void Dispose() { Dispose(true); }
. Rufen SieDispose(false)
nur aus dem finalizer und nur schreiben, wie eine in Gang gesetzt, wenn die Klasse direkt besitzt unmanged Ressourcen.InformationsquelleAutor Mike Dimmick
Persönlich, ich denke, Sie könnten besser Umgang mit diesem mit so etwas wie FxCop. Sie sollten in der Lage sein, eine Regel zu schreiben, die überprüfen, also sehen, ob, wenn ein Objekt erstellt wird, das IDisposable implementiert, dass Sie eine using-Anweisung.
Scheint es ein wenig schmutzig (für mich) automatisch dispose für ein Objekt.
InformationsquelleAutor Bryant
Es ist nicht eine "akzeptierte" Möglichkeit dies zu tun. Sie wirklich wollen, um Ihre clean-up-Logik (ob es läuft innerhalb einer Entsorgung oder einem finalizer) so einfach wie möglich, damit es nicht scheitern. Mit Reflexion innerhalb der dispose (und vor allem einen finalizer) ist allgemein eine schlechte Idee.
Soweit die Umsetzung Finalizer, im Allgemeinen, die Sie nicht brauchen, um. Finalizer fügen Sie die Kosten für Ihr Objekt und sind schwer richtig zu schreiben, da die meisten der Annahmen können Sie in der Regel machen über den Zustand des Objekts und die Laufzeit sind nicht gültig.
Sehen diese Artikel für weitere Informationen über das Dispose-Muster.
InformationsquelleAutor Scott Dorman
InformationsquelleAutor SUmeet Khandelwal
Wenn Sie verwenden wollte [basetype].Invoke("Entsorgen"...) dann könnte man implementieren Sie die Funktion aufrufen, ohne den debugger zu beschweren. Dann später, wenn die base-Typ tatsächlich die IDisposable-Schnittstelle implementiert, die es ausführen wird, der richtige Aufruf.
InformationsquelleAutor
Wenn Sie verwenden wollte [basetype].Invoke("Entsorgen"...) dann könnte man implementieren Sie die Funktion aufrufen, ohne den debugger zu beschweren. Dann später, wenn die base-Typ tatsächlich die IDisposable-Schnittstelle implementiert, die es ausführen wird, der richtige Aufruf.
InformationsquelleAutor Adam Driscoll
Versuchen. Es ist eine one-line-neben der Dispose () - Methode, und ruft die Ahnen zu entsorgen, wenn es vorhanden ist. (Beachten Sie, dass
Dispose(bool)
ist nicht Mitglied derIDisposable
)InformationsquelleAutor Steve Cooper
So, Sie verantwortlich sind, zu implementieren, zu Recht nur die erste Klasse, die IDisposable.
InformationsquelleAutor Sunny Milenov