为什么正确实现IDisposable的复杂方案?

时间:2013-03-11 19:29:15

标签: c# idisposable finalizer

今天早些时候,当我对某些代码进行代码分析时,我遇到了CA1063

我有两个问题:

  1. 为什么以下代码不会导致CA1063,即使它明显违反了某些要求(例如Dispose被覆盖)

  2. 代码的实际问题是什么导致复杂的方案有一个由密封的Dispose()和Finalizer等调用的虚拟Dispose(bool)....

  3. using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
      class Foobar : IDisposable
      {
        public Foobar()
        {
          Console.Out.WriteLine("Constructor of Foobar");
        }
    
        public virtual void Dispose()
        {
          Console.Out.WriteLine("Dispose of Foobar");
          GC.SuppressFinalize(this);
        }
    
        ~Foobar()
        {
          Console.Out.WriteLine("Finalizer of Foobar");
        }
      }
    
      class Derived : Foobar
      {
        public Derived()
        {
          Console.Out.WriteLine("Constructor of Derived");
        }
    
        public override void Dispose()
        {
          Console.Out.WriteLine("Dispose of Derived");
          GC.SuppressFinalize(this);
          base.Dispose();
        }
    
        ~Derived()
        {
          Console.Out.WriteLine("Finalizer of Derived");
        }
      }
    
      class Program
      {
        static void Main()
        {
          Console.Out.WriteLine("Start");
          using (var foo = new Derived())
          {
            Console.Out.WriteLine("...");
          }
          Console.Out.WriteLine("End");
        }
      }
    }
    

1 个答案:

答案 0 :(得分:3)

最初,Microsoft期望许多类型的对象将封装托管和非托管资源,即使特定的可继承类没有封装任何非托管资源,从它派生的类也可能这样做。即使这种想法在很大程度上是错误的(将非托管资源分离到他们自己的对象中通常要好得多,然后可以将其用作托管资源),旨在处理任意混合的托管和非托管资源的模式成为一个既定的先例

尽管完整的Dispose模式的部分是愚蠢的,但正确的简化不会遗漏很多。清理代码应该在受保护的虚方法中,以便允许派生类添加自己的逻辑但仍链接到父类方法;如果该方法的名称为Dispose,则它必须具有与无参数Dispose方法不同的签名[尽管我自己的偏好是具有不同名称的无参数方法]。我对微软模式的最大抱怨是,它要求每个派生类都有自己的逻辑来防止重复处理;让基类在非虚拟Dispose实现中处理它会更加清晰。