2009-06-18 6 views
0

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

サブクラスはどうですか?サブクラスは、パブリックメソッドとプロパティで、どのように処分されたかを知っていますか?最初に、サブクラスは削除する必要があるのは基本クラスにしかないので、サブクラスは特別な(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オブジェクトを所有し、管理していることがわかりパフォーマンスカウンター。

私はこのようなコードがある場合:WritableCounterそれが配置されていたことを、増分では、知っている可能性がどのように

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

を?単にReadableCounter/WritableCounterレベル "に配置された" メンバ変数を設定する

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

:ReadableCoutnerとWritableCounterは、単にこのようなBaseCounterの

protected virtual void Dispose(bool disposing) 

何かをオーバーライドする必要がありますか?

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

私はこれにボートを紛失していますか?

答えて

0

公開IsDisposedプロパティを持つディスポーザブルクラスをいくつか見てきました。あなたはそれを行い、あなたのサブクラスでそれをチェックすることができます。

私がやった別のことは、すべてのサブクラスメソッドが呼び出す(オーバーライドできる)汎用の保護された「検証」メソッドです。それが返ってきたら、すべてうまくいく、そうでなければ投げられるかもしれない。それはあなたのサブクラスを使い捨ての内臓から完全に隔離します。

+1

この回答とAlan McBeeの次の回答は有効だと思います。私の状況では、この答えは私が望む行動に近い(基本クラスは使い捨てで、サブクラスは使い捨てですが、実際には使い捨てリソースはありません)と考えています。私も同様のアプローチを見つけました: http://gregbeech.com/blogs/tech/archive/2007/03/07/implementing-and-using-theididposposable-interface.aspx – wageoghe

0

基本クラスとサブクラスの両方にIDisposableを実装するためのスニペットがあります。おそらくサブクラス用のものが必要でしょう。

このコードのほとんどをMSDNからスワップしました。

ここでは、基本クラスIDisposableを(あなたが望んでいないもの)のためのコードです:(これはあなたが望むコードである)

#region IDisposable Members 
// Track whether Dispose has been called. 
private bool _disposed = false; 

// Implement IDisposable. 
// Do not make this method virtual. 
// A derived class should not be able to override this method. 
public void Dispose() 
{ 
    Dispose(true); 
    // Take yourself off the Finalization queue 
    // to prevent finalization code for this object 
    // from executing a second time. 
    GC.SuppressFinalize(this); 
} 

// Dispose(bool disposing) executes in two distinct scenarios. 
// If disposing equals true, the method has been called directly 
// or indirectly by a user's code. Managed and unmanaged resources 
// can be disposed. 
// If disposing equals false, the method has been called by the 
// runtime from inside the finalizer and you should not reference 
// other objects. Only unmanaged resources can be disposed. 
protected virtual void Dispose(bool disposing) 
{ 
    // Check to see if Dispose has already been called. 
    if (!this._disposed) 
    { 
     // If disposing equals true, dispose all managed 
     // and unmanaged resources. 
     if (disposing) 
     { 
      // TODO: Dispose managed resources. 

     } 
     // Release unmanaged resources. If disposing is false, 
     // only the following code is executed. 
     // TODO: Release unmanaged resources 

     // Note that this is not thread safe. 
     // Another thread could start disposing the object 
     // after the managed resources are disposed, 
     // but before the disposed flag is set to true. 
     // If thread safety is necessary, it must be 
     // implemented by the client. 
    } 
    _disposed = true; 
} 

// Use C# destructor syntax for finalization code. 
// This destructor will run only if the Dispose method 
// does not get called. 
// It gives your base class the opportunity to finalize. 
// Do not provide destructors in types derived from this class. 
~Program() 
{ 
    // Do not re-create Dispose clean-up code here. 
    // Calling Dispose(false) is optimal in terms of 
    // readability and maintainability. 
    Dispose(false); 
} 
#endregion 

そして、ここで私は、サブクラスで使用しているコードだ:

#region IDisposable Members 
// Track whether Dispose has been called. 
private bool _disposed = false; 

// Design pattern for a derived class. 
// Note that this derived class inherently implements the 
// IDisposable interface because it is implemented in the base class. 
// This derived class does not have a Finalize method 
// or a Dispose method without parameters because it inherits 
// them from the base class. 
protected override void Dispose(bool disposing) 
{ 
    if (!this.disposed) 
    { 
     try 
     { 
      if (disposing) 
      { 
       // Release the managed resources you added in 
       // this derived class here. 
       // TODO: Dispose managed resources. 
      } 
      // Release the native unmanaged resources you added 
      // in this derived class here. 
      // TODO: Release unmanaged resources. 
      _disposed = true; 
     } 
     finally 
     { 
      // Call Dispose on your base class. 
      base.Dispose(disposing); 
     } 
    } 
} 
#endregion 

TODO:マークを探します。

関連する問題