0

管理された使い捨てリソース (.NET PerformanceCounter) を所有する基本クラスがあります。リソースで Dispose を明示的に呼び出すことができるように、クラスに IDisposable を実装することについて理解しています。私が見た例から、人々は通常、「破棄」されたプライベートブールメンバー変数を使用し、Dispose 内でそれを true に設定します。後でパブリック メソッドまたはプロパティにアクセスしようとすると、"disposed" が true の場合、ObjectDisposedException が発生します。

サブクラスではどうですか?サブクラスは、パブリック メソッドとプロパティで、それらが破棄されたことをどのように知るのでしょうか? 最初は、サブクラスは特別なこと (独自のバージョンの Dispose を実装するなど) を行う必要はないと考えていました。破棄する必要があるのは基本クラスだけだからです (サブクラスがデータを追加しないと仮定しましょう)。明示的に破棄する必要があります)、基本クラスの Dispose がそれを処理する必要があります。サブクラスは、独自の「破棄された」メンバー変数を設定するためだけに、基本クラスの仮想 Dispose メソッドをオーバーライドする必要がありますか?

これは、問題のクラス階層の非常に簡素化されたバージョンです。

class BaseCounter : IBaseCounter, IDisposable
{
  protected System.Diagnostics.PerformanceCounter pc;
  private bool disposed;
  public BaseCounter(string name)
  {
    disposed = false;
    pc = CreatePerformanceCounter(name);
  }

  #region IBaseCounter
  public string Name
  {
    get 
    {
      if (disposed) throw new ObjectDisposedException("object has been disposed");
      return pc.CounterName;
    }
  }
  public string InstanceName
  {
    get
    {
      if (disposed) throw new ObjectDisposedException("object has been disposed");
      return pc.InstanceName;
    }
  }
  #endregion IBaseCounter

  #region IDisposable
  protected virtual void Dispose(bool disposing)
  {
    if (!disposed)
    {
      if (disposing)
      {
        if (pc != null)
        {
          pc.Dispose();
        }
        pc = null;
        disposed = true;
      }
    }
  }

  public void Dispose()
  {
    Dispose(true);
  }
  #endregion IDisposable
}

class ReadableCounter : BaseCounter, IReadableCounter //my own interface
{
  public ReadableCounter(string name)
    : base(name)
  {
  }

  #region IReadableCounter 
  public Int64 CounterValue()
  {
    return pc.RawValue;
  }
  #endregion IReadableCounter
}

class WritableCounter : BaseCounter, IWritableCounter
{
  public WritableCounter(string name)
    : base(name)
  {
  }

  #region IWritableCounter 
  public Increment()
  {
    pc.Increment();
  }
  #endregion IWritableCounter
}

私たちのシステムでは、ReadableCounter と WritableCounter が BaseCounter の唯一のサブクラスであり、コード生成プロセスを介してもう 1 つのレベルにサブクラス化されるだけです。追加のサブクラス化レベルでは、特定の名前のみを追加して、名前付きカウンターに直接対応するオブジェクトを作成できるようにします (たとえば、生成されたウィジェットの数をカウントするために使用されるカウンターがある場合、最終的に WidgetCounter クラスにカプセル化されます)。 . WidgetCounter には、"WidgetCounter" パフォーマンス カウンターを作成できるようにするための知識 (実際には、文字列としてのカウンター名のみ) が含まれています。

コード生成されたクラスのみが開発者によって直接使用されるため、次のようになります。

class WritableWidgetCounter : WritableCounter
{
  public WritableWidgetCounter
    : base ("WidgetCounter")
  {
  }
}

class ReadableWidgetCounter : ReadableCounter
{
   public ReadableWidgetCounter
     : base ("WidgetCounter")
   {
   }
}

したがって、サブクラスが PerformanceCounter を使用している間に、基本クラスが PerformanceCounter オブジェクト (破棄可能) を所有および管理していることがわかります。

次のようなコードがある場合:

IWritableCounter wc = new WritableWidgetCounter();
wc.Increment();
wc.Dispose();
wc.Increment();
wc = null;

Increment で、WritableCounter は、それが破棄されたことをどのように知ることができるでしょうか? ReadableCoutner と WritableCounter は単に BaseCounter をオーバーライドする必要があります

protected virtual void Dispose(bool disposing)

このようなもの:

protected virtual void Dispose(bool disposing)
{
  disposed = true; //Nothing to dispose, simply remember being disposed
  base.Dispose(disposing); //delegate to base
}

ReadableCounter/WritableCounter レベルの「破棄」メンバー変数を設定するだけですか?

基本クラス (BaseCounter) が保護されていると宣言した (または保護されたプロパティにした) 場合はどうですか? そうすれば、単に Dispose が発生したことを思い出す目的で Dispose メソッドを追加するのではなく、サブクラスがそれを参照できます。

私はこれでボートを逃していますか?

4

2 に答える 2

0

public IsDisposed プロパティを持ついくつかの使い捨てクラスを見てきました。それを実行して、サブクラスで確認できます。

私が行ったもう 1 つのことは、すべてのサブクラス メソッドが呼び出す (そしてオーバーライドできる) 一般的な保護された 'Validate' メソッドです。返された場合はすべて問題ありませんが、そうでない場合はスローされる可能性があります。これにより、サブクラスが使い捨ての内部から完全に隔離されます。

于 2009-06-19T19:29:27.173 に答える