c# - 从派生类自动调用 base.Dispose()

标签 c# reflection idisposable

编辑 - 新问题

好的,让我们更笼统地重新表述这个问题。

有没有一种方法可以使用反射在运行时动态调用您可能正在覆盖的基类方法。您不能在编译时使用 'base' 关键字,因为您不能确定它是否存在。在运行时,我想列出我的祖先方法并调用祖先方法。

我尝试使用 GetMethods() 等,但它们返回的只是指向该方法的最派生实现的“指针”。不是基类的实现。

背景

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

问题

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

问题有两个方面。

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

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

第二部分是棘手的部分。尽管我所有的 努力,我无法从派生类调用 base.Dispose(bDisposing)。我所有的尝试都失败了。他们要么造成 编译错误或调用了错误的 Dispose() 方法,即最派生的方法,从而永远循环。

主要问题是,如果没有诸如 实现它的祖先(请注意,可能还没有实现 IDisposable 的祖先,但我希望派生代码在这种情况下准备就绪 将来会发生一件事)。这给我们留下了 Reflection 机制,但我没有找到合适的方法。我们的代码充满了 先进的反射技术,我想我没有遗漏任何明显的东西。

我的解决方案

我最好的办法是在注释代码中使用一些条件代码。更改 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 祖先历史的类中仍然可以完美地工作。

最佳答案

标准模式是让您的基类实现 IDisposable 和非虚拟 Dispose() 方法,并实现虚拟 Dispose(bool) 方法,那些持有一次性资源的类必须重写该方法。他们应该总是调用他们的基础 Dispose(bool) 方法,该方法最终将链接到层次结构中的顶级类。只有那些覆盖它的类才会被调用,所以链通常很短。

终结器,在 C# 中拼写为 ~Class:不要。很少有类需要一个,并且很容易意外地保留大对象图,因为终结器在释放内存之前至少需要两次集合。在对象不再被引用后的第一个集合中,它被放入要运行的终结器队列中。它们在单独的专用线程上运行,该线程仅运行终结器(如果它被阻塞,则不再运行终结器并且您的内存使用量激增)。一旦终结器运行,收集适当世代的下一个集合将释放该对象以及它所引用但未被引用的任何其他对象。不幸的是,因为它在第一次收集中幸存下来,所以它将被放入收集频率较低的老年代。因此,您应该尽早并经常处置。

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

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

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

关于c# - 从派生类自动调用 base.Dispose(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/78141/

相关文章:

c# - StructureMap 开放通用类型

c# - 二维数组 ext.net GridView

c# - 这段代码中的设计模式是什么?

java - 使用反射获取Java中泛型参数的类型

c# - 微软的dispose模式结构的原因是什么?

c# - Delphi DLL 可以在 C# 中调用和使用吗?

java - 将 Protocol Buffer 序列化为 XML?

.net - 处置时托管资源和 native 资源有什么区别? (。网)

c# - 关于using语句的一些高级问题

c# - 按最近日期排序并将相似标题聚类(分组)