Edit - New Question
Ok lets rephrase the question more generically.
Using reflection, is there a way to dynamically call at runtime a base class method that you may be overriding. You cannot use the 'base' keyword at compile time because you cannot be sure it exists. At runtime I want to list my ancestors methods and call the ancestor methods.
I tried using GetMethods() and such but all they return are "pointers" to the most derived implementation of the method. Not an implementation on a base class.
Background
We are developing a system in C# 3.0 with a relatively big class hierarchy. Some of these classes, anywhere in the hierarchy, have resources that need to be disposed of, those implement the IDisposable interface.
The Problem
Now, to facilitate maintenance and refactoring of the code I would like to find a way, for classes implementing IDisposable, to "automatically" call base.Dispose(bDisposing) if any ancestors also implements IDisposable. This way, if some class higher up in the hierarchy starts implementing or stops implementing IDisposable that will be taken care of automatically.
The issue is two folds.
- First, finding if any ancestors implements IDisposable.
- Second, calling base.Dispose(bDisposing) conditionally.
The first part, finding about ancestors implementing IDisposable, I have been able to deal with.
The second part is the tricky one. Despite all my efforts, I haven't been able to call base.Dispose(bDisposing) from a derived class. All my attempts failed. They either caused compilation errors or called the wrong Dispose() method, that is the most derived one, thus looping forever.
The main issue is that you cannot actually refer to base.Dispose() directly in your code if there is no such thing as an ancestor implementing it (be reminded that there might have no ancestors yet implementing IDisposable, but I want the derived code to be ready when and if such a thing happens in the future). That leave us with the Reflection mechanisms, but I did not find a proper way of doing it. Our code is quite filled with advanced reflection techniques and I think I did not miss anything obvious there.
My Solution
My best shot yet was to have some conditional code using in commented code. Changing the IDisposable hierarchy would either break the build (if no IDisposable ancestor exists) or throw an exception (if there are IDisposable ancestors but base.Dispose is not called).
Here is some code I am posting to show you what my Dispose(bDisposing) method looks like. I am putting this code at the end of all the Dispose() methods throughout the hierarchy. Any new classes are created from templates that also includes this 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, I am asking is there a way to call base.Dispose() automatically/conditionally instead?
More Background
There is another mechanism in the application where all objects are registered with a main class. The class checks if they implement IDisposable. If so, they are disposed of properly by the application. This avoids having the code using the classes to deal with calling Dispose() all around by themselves. Thus, adding IDisposable to a class that has no ancestor history of IDisposable still works perfectly.