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

时间:2008-09-16 22:53:15

标签: c# reflection idisposable

编辑 - 新问题

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

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

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

背景

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

问题

现在,为了便于维护和重构代码,我想找到一种方法,对于实现IDisposable的类, 如果任何祖先也实现了IDisposable,则“自动”调用 base.Dispose(bDisposing)。这样,如果层次结构中的某些类开始实现 或者停止实施将自动处理的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());
            }
        }
    }
}

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

更多背景

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

8 个答案:

答案 0 :(得分: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,它生成代码当表单设置处置 - 这反过来部署所有已添加的组件。对于移动项目,生成Dispose components的代码,但是将组件放到曲面上不会生成将其添加到components 的代码。在调用InitializeComponent之后,你必须在构造函数中自己完成这个。

答案 1 :(得分:3)

就个人而言,我认为用FxCop之类的东西处理这个问题可能会更好。您应该能够编写一个检查规则,以便查看是否创建了一个实现IDisposable的对象,并使用了using语句。

自动处理对象似乎有点脏(对我而言)。

答案 2 :(得分:2)

没有“接受”的方式这样做。你真的想让你的清理逻辑(无论是在Dispose还是finalizer中运行)尽可能简单,这样它就不会失败。使用dispose(特别是终结器)内部的反射通常是一个坏主意。

就实施终结者而言,通常你不需要。终结器为您的对象增加了成本,并且难以正确编写,因为您通常可以对对象状态和运行时进行的大多数假设都无效。

有关Dispose模式的详细信息,请参阅此article

答案 3 :(得分:2)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestDisposeInheritance
{
    class Program
    {
        static void Main(string[] args)
        {
            classC c = new classC();
            c.Dispose();
        }
    }

    class classA: IDisposable 
    { 
        private bool m_bDisposed;
        protected virtual void Dispose(bool bDisposing)
        {
            if (!m_bDisposed)
            {
                if (bDisposing)
                {
                    // Dispose managed resources
                    Console.WriteLine("Dispose A"); 
                }
                // Dispose unmanaged resources 
            }
        }
        public void Dispose() 
        {
            Dispose(true);
            GC.SuppressFinalize(this);
            Console.WriteLine("Disposing A"); 
        } 
    } 

    class classB : classA, IDisposable 
    {
        private bool m_bDisposed;
        public void Dispose()
        {
            Dispose(true);
            base.Dispose();
            GC.SuppressFinalize(this);
            Console.WriteLine("Disposing B");
        }

        protected override void Dispose(bool bDisposing)
        {
            if (!m_bDisposed)
            {
                if (bDisposing)
                {
                    // Dispose managed resources
                    Console.WriteLine("Dispose B");
                }
                // Dispose unmanaged resources 
            }
        }
    } 

    class classC : classB, IDisposable 
    {
        private bool m_bDisposed;
        public void Dispose() 
        {
            Dispose(true);
            base.Dispose();
            GC.SuppressFinalize(this);
            Console.WriteLine("Disposing C");             
        }
        protected override void Dispose(bool bDisposing)
        {
            if (!m_bDisposed)
            {
                if (bDisposing)
                {
                    // Dispose managed resources
                    Console.WriteLine("Dispose C");             
                }
                // Dispose unmanaged resources 
            }
        }
    } 

}

答案 4 :(得分:0)

如果你想使用[basetype] .Invoke(“Dispose”...)那么你可以在没有调试器抱怨的情况下实现函数调用。然后,当基类型实际实现IDisposable接口时,它将执行正确的调用。

答案 5 :(得分:0)

如果你想使用[basetype] .Invoke(“Dispose”...)那么你可以在没有调试器抱怨的情况下实现函数调用。然后,当基类型实际实现IDisposable接口时,它将执行正确的调用。

答案 6 :(得分:0)

public class MyVeryBaseClass {
    protected void RealDispose(bool isDisposing) {
        IDisposable tryme = this as IDisposable;
        if (tryme != null) { // we implement IDisposable
            this.Dispose();
            base.RealDispose(isDisposing);
        }
    }
}
public class FirstChild : MyVeryBaseClasee {
    //non-disposable
}
public class SecondChild : FirstChild, IDisposable {
    ~SecondChild() {
        Dispose(false);
    }
    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
        base.RealDispose(true);
    }
    protected virtual void Dispose(bool bDisposing) {
        if (!m_bDisposed) {
            if (bDisposing) {
            }// Dispose managed resources
        } // Dispose unmanaged resources
    }
}

这样,你只负责实现IDisposable的第一个类。

答案 7 :(得分:0)

试试这个。它是Dispose()方法的一行添加,并调用祖先的dispose(如果存在)。 (请注意,Dispose(bool)不是IDisposable

的成员
// Disposal Helper Functions
public static class Disposing
{
    // Executes IDisposable.Dispose() if it exists.
    public static void DisposeSuperclass(object o)
    {
        Type baseType = o.GetType().BaseType;
        bool superclassIsDisposable = typeof(IDisposable).IsAssignableFrom(baseType);
        if (superclassIsDisposable)
        {
            System.Reflection.MethodInfo baseDispose = baseType.GetMethod("Dispose", new Type[] { });
            baseDispose.Invoke(o, null);
        }
    }
}

class classA: IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("Disposing A");
    }
}

class classB : classA, IDisposable
{
}

class classC : classB, IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("Disposing C");
        Disposing.DisposeSuperclass(this);
    }
}