Pergunta

Earlier today I ran into CA1063 when running code analysis on some code at work.

I have two questions:

  1. Why does the following code not cause CA1063 even though it clearly violates some of the demands (for example Dispose is overridden)

  2. What is the actual problem with the code that caused the complicated scheme for having a virtual Dispose(bool) that is called by a sealed Dispose() and the Finalizer and so on....

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");
    }
  }
}
Foi útil?

Solução

Originally, Microsoft expected that many types of objects would encapsulate both managed and unmanaged resources, and that even if a particular inheritable class did not encapsulate any unmanaged resources, a class which derived from it might do so. Even though such thinking was largely wrong (it's usually much better to segregate unmanaged resources into their own objects, which may then be used as managed resources), the pattern that was designed to deal with arbitrarily-mixed managed and unmanaged resources became an established precedent.

Even though parts of the full Dispose pattern are silly, a proper simplification wouldn't leave out a whole lot. The cleanup code should be in a protected virtual method, so as to allow derived classes to add their own logic but still chain to the parent-class method; if that method is given the name Dispose, it must have a signature distinct from that of a parameterless Dispose method [though my own preference would be a parameterless method with a different name]. My biggest complaint with Microsoft's pattern is that it requires every derived class to have its own logic to protect against repeated disposal; it would have been much cleaner to have the base class take care of that in the non-virtual Dispose implementation.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top