編集 - 新しい質問
わかりました、質問をより一般的に言い換えましょう。
リフレクションを使用して、オーバーライドしている可能性のある基本クラス メソッドを実行時に動的に呼び出す方法はありますか。'base' キーワードが存在することを確認できないため、コンパイル時には使用できません。実行時に祖先のメソッドを一覧表示し、祖先のメソッドを呼び出したいと思います。
GetMethods() などを使用してみましたが、返されるのはメソッドの最も派生した実装への「ポインター」だけです。基本クラスでの実装ではありません。
バックグラウンド
比較的大きなクラス階層を持つ C# 3.0 でシステムを開発しています。これらのクラスの一部は、階層内の任意の場所に、破棄する必要のあるリソースがあり、それらはIDisposableインターフェイスを実装しています。
問題
ここで、コードのメンテナンスとリファクタリングを容易にするために、IDisposable を実装するクラスについて、先祖も IDisposable を実装している場合にbase.Dispose(bDisposing)を「自動的に」呼び出す方法を見つけたいと思います。このようにして、階層の上位にあるクラスが IDisposable の実装を開始または停止した場合、自動的に処理されます。
問題は二重です。
- まず、先祖が IDisposable を実装しているかどうかを調べます。
- 次に、base.Dispose(bDisposing) を条件付きで呼び出します。
最初の部分では、先祖が IDisposable を実装していることを発見し、対処することができました。
2番目の部分はトリッキーです。すべての努力にもかかわらず、派生クラスから base.Dispose(bDisposing) を呼び出すことができませんでした。私の試みはすべて失敗しました。それらはコンパイル エラーを引き起こしたか、最も派生したメソッドである間違った Dispose() メソッドを呼び出したため、永遠にループしていました。
主な問題は、 base.Dispose()を実装する先祖などがない場合、コード内で直接base.Dispose() を実際に参照できないことです ( IDisposable をまだ実装している祖先がない可能性があることを思い出してください。ただし、派生コードを将来そのようなことが起こった場合に備えてください)。これでリフレクションメカニズムが残りましたが、それを行う適切な方法が見つかりませんでした。私たちのコードは高度なリフレクション テクニックでいっぱいで、明らかな見落としはなかったと思います。
私の解決策
私の最善の策は、コメント付きのコードで使用する条件付きコードをいくつか用意することでした。IDisposable 階層を変更すると、ビルドが中断されるか (IDisposable の祖先が存在しない場合)、例外がスローされます (IDisposable の祖先が存在するが base.Dispose が呼び出されない場合)。
Dispose(bDisposing) メソッドがどのように見えるかを示すために投稿しているコードを次に示します。このコードを、階層全体のすべての Dispose() メソッドの最後に配置しています。新しいクラスは、このコードも含むテンプレートから作成されます。
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());
}
}
}
}
だから、代わりに base.Dispose() を自動的に/条件付きで呼び出す方法はありますか?
その他の背景
アプリケーションには、すべてのオブジェクトがメイン クラスに登録される別のメカニズムがあります。クラスは、IDisposable を実装しているかどうかを確認します。その場合、それらはアプリケーションによって適切に破棄されます。これにより、コードがクラスを使用して Dispose() の呼び出しを処理する必要がなくなります。したがって、IDisposable の先祖の履歴がないクラスに IDisposable を追加しても、完全に機能します。