3

今日の初めに、作業中のコードでコード分析を実行しているときにCA1063に遭遇しました。

2つの質問があります:

  1. 次のコードが、一部の要求に明らかに違反しているにもかかわらず、CA1063を引き起こさないのはなぜですか(たとえば、Disposeがオーバーライドされます)

  2. 封印されたDispose()やファイナライザーなどによって呼び出される仮想Dispose(bool)を持つための複雑なスキームを引き起こしたコードの実際の問題は何ですか?

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");
    }
  }
}
4

1 に答える 1

5

当初、Microsoftは、多くの種類のオブジェクトがマネージリソースとアンマネージリソースの両方をカプセル化すること、および特定の継承可能なクラスがアンマネージリソースをカプセル化しない場合でも、それから派生したクラスがカプセル化することを期待していました。そのような考え方はほとんど間違っていましたが(通常、管理されていないリソースを独自のオブジェクトに分離し、それを管理されたリソースとして使用する方がはるかに優れています)、任意に混合された管理されたリソースと管理されていないリソースを処理するように設計されたパターンは、確立された前例になりました。

完全なDisposeパターンの一部はばかげていますが、適切に単純化しても、全体を除外することはできません。派生クラスが独自のロジックを追加できるように、クリーンアップコードは保護された仮想メソッド内にある必要がありますが、それでも親クラスメソッドにチェーンされます。そのメソッドに名前が付けられている場合は、パラメーターなしのメソッドとは異なるDisposeシグニチャーが必要です[ただし、私自身の好みは、別の名前のパラメーターなしのメソッドです]。DisposeMicrosoftのパターンに対する私の最大の不満は、すべての派生クラスが繰り返しの廃棄から保護するための独自のロジックを持っている必要があるということです。非仮想Dispose実装で基本クラスにそれを処理させる方がはるかにクリーンでした。

于 2013-03-11T21:06:52.233 に答える