从派生类中自动调用base.Dispose()

Phi*_*sse 2 c# reflection idisposable

编辑 - 新问题

好的,让我们更一般地重新解释这个问题.

使用反射,有没有办法在运行时动态调用您可能重写的基类方法.您不能在编译时使用'base'关键字,因为您无法确定它是否存在.在运行时,我想列出我的祖先方法并调用祖先方法.

我尝试使用GetMethods()等,但他们返回的只是指向该方法派生程序最多的"指针".不是基类的实现.

背景

我们正在使用相对较大的类层次结构在C#3.0中开发一个系统.这些类中的一些类(在层次结构中的任何位置)具有需要处理的资源,这些类实现IDisposable接口.

问题

现在,为了便于维护和重构代码,我想找到一种方法,对于实现IDisposable的类,"自动"调用base.Dispose(bDisposing),如果任何祖先也实现了IDisposable.这样,如果层次结构中较高级别的某个类开始实现或停止实现将自动处理的IDisposable.

这个问题有两个方面.

  • 首先,查找是否有任何祖先实现IDisposable.
  • 其次,有条件地调用base.Dispose(bDisposing).

第一部分,找到实现IDisposable的祖先,我已经能够处理.

第二部分是棘手的.尽管我付出了很多努力,但我还是无法从派生类调用base.Dispose(bDisposing).我所有的尝试都失败了 它们要么导致编译错误,要么调用错误的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());
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,我问有没有办法自动/有条件地调用base.Dispose()?

更多背景

应用程序中还有另一种机制,其中所有对象都使用主类注册.该类检查它们是否实现了IDisposable.如果是这样,它们将被应用程序正确处理.这避免了使用类来处理自己调用Dispose()的代码.因此,将IDisposable添加到没有IDisposable的祖先历史的类仍然可以正常工作.

Mik*_*ick 9

标准模式是您的基类实现IDisposable和非虚拟Dispose()方法,并实现虚拟Dispose(bool)方法,其中包含可支配资源的类必须覆盖.他们应该总是调用他们的基础Dispose(bool)方法,它最终将链接到层次结构中的顶级类.只会调用覆盖它的那些类,因此链通常很短.

终结者,拼写~C#中的类:不要.很少有类需要一个,并且很容易意外地保留大对象图,因为终结器在释放内存之前至少需要两个集合.在对象不再被引用之后的第一个集合上,它被放置在要运行的终结器队列中.这些是在一个单独的专用线程上运行的它只运行终结器(如果它被阻止,不再运行终结器并且你的内存使用量会爆炸).终结器运行后,收集适当生成的下一个集合将释放该对象及其引用的任何其他未引用的内容.不幸的是,因为它在第一次收集中存活下来,所以它将被放置在较不经常收集的老一代中.出于这个原因,你应该尽早和经常处理.

通常,您应该实现一个小资源包装器类,它只管理资源生命周期并在该类上实现终结器,以及IDisposable.然后,类的用户应该在处理时调用Dispose.不应该有用户的反向链接.这样,只有实际需要终结的东西才会终结于终结队列.

如果您将在层次结构中的任何位置需要它们,则实现IDisposable的基类应实现终结器并调用Dispose(bool),并将false作为参数传递.

Windows Mobile开发人员的警告(VS2005和2008,.NET Compact Framework 2.0和3.5):您放入设计器界面的许多非控件,例如菜单栏,计时器,HardwareButtons,派生自System.ComponentModel.Component,它实现了终结.对于桌面项目,Visual Studio将组件添加到名为System.ComponentModel.Container components,它在窗体Disposed时生成Dispose代码 - 它依次释放已添加的所有组件.对于移动项目,将components生成Dispose代码,但将组件放到曲面上不会生成要添加的代码components.在调用InitializeComponent之后,您必须在构造函数中自己完成此操作.