C# 从派生类自动调用base.Dispose() 编辑-新问题

C# 从派生类自动调用base.Dispose() 编辑-新问题,c#,reflection,idisposable,C#,Reflection,Idisposable,好吧,让我们更笼统地重新表述这个问题 使用反射,是否有一种方法可以在运行时动态调用您可能要重写的基类方法。您不能在编译时使用'base'关键字,因为您不能确定它是否存在。在运行时,我想列出我的祖先方法并调用祖先方法 我尝试使用GetMethods()等,但它们返回的都是指向该方法最派生的实现的“指针”。不是基类上的实现 背景 我们正在用C#3.0开发一个具有相对较大的类层次结构的系统。这些类中的一些,在层次结构中的任何地方,都有需要更新的资源 处理后,它们实现了IDisposable接口 问题

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

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

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

背景 我们正在用C#3.0开发一个具有相对较大的类层次结构的系统。这些类中的一些,在层次结构中的任何地方,都有需要更新的资源 处理后,它们实现了IDisposable接口

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

问题有两个方面

  • 首先,查找是否有祖先实现了IDisposable
  • 第二,有条件地调用base.Dispose(bDisposing)
第一部分,关于实现IDisposable的祖先的发现,我已经能够处理了

第二部分是棘手的问题。尽管我 但是,我无法从派生类调用base.Dispose(bDisposing)。我所有的尝试都失败了。他们要么造成 编译错误或调用了错误的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祖先历史的类中仍然可以很好地工作。

就个人而言,我认为您最好使用FxCop之类的工具来处理这个问题。您应该能够编写一个规则来检查是否在创建实现IDisposable的对象时使用using语句


(对我来说)自动处理对象似乎有点脏。

如果您想使用[basetype].Invoke(“dispose”…),那么您就可以实现函数调用,而无需调试器抱怨。然后,当基类型实际实现IDisposable接口时,它将执行正确的调用。

如果要使用[basetype].Invoke(“Dispose”…),则可以在调试器不抱怨的情况下实现函数调用。然后,当基类型实际实现IDisposable接口时,它将执行适当的调用。

标准模式是让基类实现IDisposable和非虚拟Dispose()方法,并实现虚拟Dispose(bool)方法,持有可处置资源的类必须覆盖该方法。他们应该始终调用他们的基本Dispose(bool)方法,该方法最终将链接到层次结构中的顶级类。只有覆盖它的类才会被调用,因此链通常很短

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

通常,您应该实现一个只管理资源生存期的小型资源包装类,并在该类上实现一个终结器,以及IDisposable。然后,该类的用户应在释放时对此调用Dispose。不应该有到用户的反向链接。这样,只有真正需要终结的东西才会在终结队列中结束

如果你在任何地方都需要它们
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
    }
}
// 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);
    }
}
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 
            }
        }
    } 

}