1

私は以下のケースを扱っています。IDisposableパターンを持つ基本クラスがあります。これは、public virtual Dispose()メソッドとメソッドがあることを意味しprotected virtual Dispose(bool)ます。ただし、CAの警告を受け取らないように、このパターンを派生クラスに実装することはできません。次の例を検討してください。

public class UtilizeClass : IDisposable
{
    private MyData data;

    public UtilizeClass()
    {
        data = new MyData();
    }

    public void Dispose()
    {
        data.Dispose(); // Cannot use Dispose(bool) because it is protected.
    }
}

public class MyData : Base, IDisposable
{
    // Here we have some managed resources that must be disposed.

    // How to implement the pattern?
}

public class Base : IDisposable
{
    public virtual void Dispose() { }
    protected virtual void Dispose(bool disposing) { }
}

クラスで常に矛盾するCAの警告を受け取りますMyData。例:Dispose()を削除し、ロジックをDispose(bool)に移動します。

答えと助けてくれてありがとう。

4

3 に答える 3

2

基本クラスは仮想である必要はありません。実装され、実装の一部としてvoid Dispose()仮想を呼び出す必要があります。void Dispose(bool disposing)

詳細と、もう少し明確な代替APIについては、以下を確認してください。

http://haacked.com/archive/2005/11/18/acloserlookatdisposepattern.aspx

于 2012-08-03T12:42:15.333 に答える
2

が独自のクラスである場合Baseは、このアンチパターンを実装しないでください。

2つ折りのdispose(disposedがtrueの場合は1つ、falseの場合は1つ)は、クラスに破棄する必要のあるマネージリソース(たとえば、独自に呼び出されるStreamオブジェクトDispose)とクリーンアップする必要のあるアンマネージリソースの両方が含まれる場合に使用されます-上。

これは悪い考えです。代わりに、すべてのクラスを1つまたは2つのカテゴリに当てはめてください。

A.管理されていないリソースのみを持つクラス。理想的には、クラスごとに1つだけです。

public sealed class HandlesUnmanaged : IDisposable
{
  private IntPtr _someUnmanagedHandleOfSomeKind;
  public string DoSomething(string someParam)
  {
    // your useful code goes here;
    // make it thin, non-virtual and likely to be inlined
    // if you need to extend functionality, but it in a
    // containing Disposable class, not a derived class.
  }
  private void CleanUp()
  {
    //your code that cleans-up someUnmanagedHandleOfSomeKind goes here
  }
  public void Dispose()
  {
    CleanUp();
    GC.SuppressFinalize(this);//finaliser not needed now.
  }
  ~HandlesUnmanaged()//not called if already disposed
  {
    CleanUp();
  }
}

理想的には、このようなクラスは必要ありませんが、それを使用SafeHandleしてください。

B.廃棄する必要のある1つ以上の管理対象リソースを持つクラス:

public class NoUnmanaged : IDisposable
{
  private HandlesUnmanaged _likeAbove;
  private Stream _anExampleDisposableClass;
  public virtual void Dispose()
  {
    _likeAbove.Dispose();
    _anExampleDisposableClass.Dispose();
  } 
  /* Note no finaliser, if Dispose isn't called, then _likeAbove's
  finaliser will be called anyway. All a finaliser here would do is
  slow things up and possibly introduce bugs.
  */
}
public class DerivedNoUnManaged : NoUnmanaged
{
  Stream _weMayOrMayNotHaveAnotherDisposableMember;
  public override void Dispose()
  {
    //note we only need this because we have
    //another disposable member. If not, we'd just inherit
    //all we need.
    base.Dispose();
    weMayOrMayNotHaveAnotherDisposableMember.Dispose();
  }
}

Dispose()全体として、前者の呼び出しを除いて、ファイナライザーとファイナライザーで同じことを行う単純な非管理所有クラスがあるか、または、以下を含むすべてを破棄する必要GC.SuppressFinalizeがある単純な非管理所有クラスがあります。必要に応じDispose()て電話をかけ、base.Dispose()ファイナライザーはありません。同じクラス内でロジックを2つのタイプに分割する必要はありません。ファイナライザーがファイナライズされたものを呼び出したり、必要以上にファイナライズキューに入れたりするリスクはありません。

そして理想的には、最初のタイプをまったく実行しないことです。ちょうど2番目のタイプ。

他のパーティのクラスから継承することによって強制された場合は、次のようにします。

public MyClass : Base
{
  Stream _forExample;
  public override void Dispose(bool disposing)
  {
    if(disposing)
    {
      _forExample.Dispose();
    }
    base.Dispose(disposing);
  }
}

disposing == false管理されていないリソースが混在していないため、自分でケースを処理しないでください。

于 2012-08-03T13:01:48.460 に答える
0

基本クラスには、public void Dispose()を呼び出す(非仮想)が必要Dispose(true)です。

派生クラスは単にをオーバーライドする必要がありますprotected virtual void Dispose(bool disposing)

于 2012-08-03T12:42:19.793 に答える