Bearbeiten - Neue Frage
Okay, formulieren wir die Frage etwas allgemeiner.
Gibt es eine Möglichkeit, mit Hilfe von Reflection zur Laufzeit dynamisch eine Basisklassenmethode aufzurufen, die Sie möglicherweise überschreiben. Sie können das Schlüsselwort "base" nicht zur Kompilierzeit verwenden, da Sie nicht sicher sein können, dass es existiert. Zur Laufzeit möchte ich meine Vorgängermethoden auflisten und die Vorgängermethoden aufrufen.
Ich habe versucht, mit GetMethods() und so weiter, aber alles, was sie zurückgeben, sind "Zeiger" auf die meisten abgeleiteten Implementierung der Methode. Nicht eine Implementierung auf einer Basisklasse.
Hintergrund
Wir entwickeln ein System in C# 3.0 mit einer relativ großen Klassenhierarchie. Einige dieser Klassen, irgendwo in der Hierarchie, haben Ressourcen, die entsorgt werden müssen, diese implementieren die IDer Einwegartikel Schnittstelle.
Das Problem
Um die Wartung und das Refactoring des Codes zu erleichtern, möchte ich nun eine Möglichkeit finden, für Klassen, die IDisposable, "automatisch" aufzurufen base.Dispose(bDisposing) wenn einer der Vorfahren ebenfalls IDisposable implementiert. Auf diese Weise kann eine Klasse, die in der Hierarchie weiter oben steht, wenn sie implementiert oder aufhört, IDisposable zu implementieren, wird dies automatisch behoben.
Das Problem ist ein zweifaches.
- Zunächst wird festgestellt, ob ein Vorfahr IDisposable implementiert.
- Zweitens: Bedingter Aufruf von base.Dispose(bDisposing).
Den ersten Teil, die Suche nach Vorfahren, die IDisposable implementieren, habe ich bewältigen können.
Der zweite Teil ist der heikle Teil. Trotz all meiner Bemühungen ist es mir nicht gelungen, base.Dispose(bDisposing) aus einer abgeleiteten Klasse aufzurufen. Alle meine Versuche schlugen fehl. Sie verursachten entweder Kompilierungsfehler oder riefen die falsche Dispose()-Methode auf, d. h. die am meisten abgeleitete Methode, was zu einer Endlosschleife führte.
Das Hauptproblem ist, dass Sie kann nicht tatsächlich auf base.Dispose() verweisen direkt in Ihren Code einfügen, wenn es kein solches Element wie Vorgänger gibt, der es implementiert ( daran erinnert werden, dass es vielleicht noch keine Vorfahren gibt, die IDisposable implementieren, aber ich möchte, dass der abgeleitete Code bereit ist, wenn und falls solche so etwas in der Zukunft passiert ). Damit bleibt uns die Reflexion Mechanismen, aber ich habe keinen geeigneten Weg gefunden, dies zu tun. Unser Code ist ziemlich voll mit fortgeschrittenen Reflexionstechniken, und ich denke, ich habe dort nichts Offensichtliches übersehen.
Meine Lösung
Mein bester Versuch war es, einige bedingte Code mit in kommentierten Code haben. Eine Änderung der IDisposable-Hierarchie würde entweder den Build unterbrechen (wenn kein IDisposable-Vorfahr existiert) oder eine Ausnahme auslösen (wenn es IDisposable-Vorfahren gibt, aber base.Dispose nicht aufgerufen wird).
Im folgenden Code zeige ich Ihnen, wie meine Methode Dispose(bDisposing) aussieht. Ich füge diesen Code an das Ende aller Dispose() Methoden in der gesamten Hierarchie. Alle neuen Klassen werden aus Vorlagen erstellt, die auch diesen Code enthalten.
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());
}
}
}
}
Also, ich frage, gibt es eine Möglichkeit, base.Dispose() automatisch/bedingte stattdessen aufrufen?
Mehr Hintergrund
Es gibt einen weiteren Mechanismus in der Anwendung, bei dem alle Objekte bei einer Hauptklasse registriert werden. Die Klasse prüft, ob sie IDisposable implementieren. Ist dies der Fall, werden sie von der Anwendung ordnungsgemäß entsorgt. Dadurch wird vermieden, dass der Code, der die Klassen verwendet, sich mit Dispose() aufzurufen. Daher funktioniert das Hinzufügen von IDisposable zu einer Klasse, die keine Vorfahren von IDisposable hat, immer noch perfekt.