2012-03-11 1 views
2

私はan OSS projectに取り組んでいます。人気のあるMediaInfo libraryを.NETで使いやすくしていますが、この質問は一般化可能です。どのクラスがアンマネージリソースを所有していますか(そしてIDisposableを実装していますか?)

派生クラスDは常にオブジェクトOその基底クラスDBのコンストラクタを呼び出すインスタンス化する場合。 DBは、コンストラクタに送られたものにその値を設定し、その値自体はで宣言されDBの基本クラスB

以下のコードで O(AKA MediaInfoをを 『所有』
  1. )?
  2. .NETアプリケーションの場合、これらのうちどれがIDisposableを実装する必要がありますか? 注:Oは管理されていないか、少なくともアンマネージライブラリをラップした管理対象オブジェクトのインスタンスですが、 "MediaInfo.Close();"の形式でクリーンアップする必要があります。私はこのことが「管理されていない」とは確信していません。

私は実際のコードを使用させ、明確に支援するため:はDB由来

D:Bに由来するそのO継承を設定

// MediaFile is "D" 
public sealed class MediaFile : GeneralStream 
{ 
    public MediaFile(string filePath) 
     : base(new MediaInfo(), 0) { 
     // mediaInfo is "O" 
     mediaInfo.Open(filePath); 
    } 
} 

DBを

// GeneralStream is "DB" 
public abstract class GeneralStream : StreamBaseClass 
{ 
    public GeneralStream(MediaInfo mediaInfo, int id) { 
     this.mediaInfo = mediaInfo; // declared in StreamBaseClass 
     // ... 
    } 
} 

BOを宣言:

// StreamBaseClass is "B" 
public abstract class StreamBaseClass 
{ 
    protected MediaInfo mediaInfo; // "O" is declared 
    // ... 
} 
+0

異なる 'Stream'タイプは既に' IDisposable'を実装しています - これは、それらのいずれかから継承するクラスがこの実装を継承することを意味します。 – Oded

+0

@Oded、私は質問の中のストリームが何か異なっていると思います。彼らは 'System.IO.Stream'から継承しません。 – svick

+0

@svick - 私は同意しますが、BCLの 'Stream'とそれに関連する型はインタフェースを実装していると指摘しました。 – Oded

答えて

2

リソースへの参照を保持するオブジェクトがそれを所有します。

StreamBaseClassは参照番号mediaInfoを持ち、IDisposableを実装する必要があります。参照メソッドとDisposeメソッドは、自動的に派生クラスに継承されます。

+0

リソースへの参照が所有されていても、所有権を意味するものではありません。リソースへの* only *参照の所有権は所有権を意味します(他の誰も参照を保持していない場合、誰もそれをクリーンアップすることはできません)が、いくつかの異なるクラスオブジェクト間でリソースが共有される場合があります。 'Disposed 'になるオブジェクトの最初のものがリソースに対して' Dispose'を呼び出す場合、それを使用する他の誰かを混乱させるでしょう。 – supercat

+0

はい、ここでチャールズは私たちにクラス階層を示しています。これにはいくつかのクラスが含まれますが、必ずしもいくつかのクラスが必要です。 –

+0

基本クラスはコンストラクタに 'MediaInfo'を受け取っていることを知っていますが、コンストラクタのコントラクトがそのリソースの所有権を明示的に宣言している場合を除き、呼び出し側も呼び出し側も、渡されたリソース。リソースをパラメータとして受け入れるコンストラクタはpublicであるため、この特定のケースでは連鎖呼び出しとして呼び出されることもありますが、必ずしもそうであるとは限りません。 – supercat

1

クラスCは、IDisposableインターを実装非露光ローカル変数Vである変数を所有している場合、CはIDisposableをとCのIDisposableをなければなりません

クラスDがネイティブリソースNを所有する場合、DはIDisposable(Nを削除する)であり、にfinalizabあなたがIDisposableを持っていれば、あなたはそれをDispose()する必要があります。それが完了すると、すべて削除されます。オブジェクトツリーの途中で誰かがあなたを忘れてしまった場合(読者:同僚、あなたの図書館のユーザーなど)は、ネイティブリソースがDのファイナライザによってクリーンアップされるため、オブジェクトをリークしません。

1

IDisposableの責任は、を作成するオブジェクトに属します。それ以外の明示的な同意がない場合は、が作成されます。リソースの作成者が消費者の生涯を知らない場合には、反対の約束が一般的に使用されます。多くの場合、コンストラクタまたはファクトリメソッドが、渡されたIDisposableの最後のコンシューマである可能性のあるものを生成している場合、そのメソッドはDisposeを呼び出す責任を受け入れるべきかどうかを示すパラメータを受け入れるか、またはコールバック代理人非nullの場合は、コンシューマがオブジェクトを必要としなくなったときに呼び出されます。オブジェクトの作成者がコンシューマーより長生きすると、nullを渡すことができます。作成者が一度オブジェクトを渡してもオブジェクトの使用がない場合は、オブジェクトのDisposeメソッドを渡すことができます。作成者が消費者の寿命を過ぎるかどうかわからない場合は、オブジェクトがまだ必要かどうかを判断するメソッドを渡し、そうでない場合はDisposeを呼び出します。

具体的には、チェーンコンストラクタコール内にIDisposableを作成することは、リソースリークのレシピです(try-finallyブロックにチェーンコンストラクタ呼び出しをラップする方法がないため)。あなたが何とか安全に扱うなら(例えば、チェーンコンストラクタでなくファクトリメソッドを使うか、または[threadstatic]ハックを使って)、私は、オブジェクトの作成者(派生クラス)が消費者(基本クラス)、所有権およびクリーンアップの責任は、オブジェクト作成者にとどまるべきです。

+0

スーパーキャットはIDisposableをクリエイターが実装し、Olivier Jacot-Descombesはリファレンス所有者でなければならないことを示唆しています。私は明確な「正しい」答えが得られることを期待していましたが、あなたは両方とも印象的な評判を持ち、意見が一致していないようです。 私の特定のケースでは、アンマネージドオブジェクトは本質的に不変であることに役立ちますか?これをコードでまだ強制していませんが、使用モデルは、GeneralStreamがインスタンス化され、派生MediaInfoが決して変更されないというものです。 –

+1

@Charles:ある時点で、 'IDisposable'が作成されてから破壊されるまでに、' Dispose'が呼び出されることを確実にするための責任があると特定できるオブジェクトまたはスコープブロックが存在するはずです。それ自体を世話したり、他のオブジェクトやスコープブロックを持つことによってそれを世話することが約束されています。多くの場合、オブジェクトがそのコンストラクタに 'IDisposable'を受け入れることに何も問題はなく、もはや必要がなくなったときに' Dispose'を呼び出すという契約に同意しますが、この責任の仮定は文書化されるべきであり、推測されるべきではありません。 – supercat

+0

私はStreamBaseClassの両方が参照を保持し、IDisposableを実装するようにあなたの提案(私は思う)をとり、コードを変更しました。アンマネージド部分が開くファイルパスはStreamBaseClassに2つのコンストラクタで渡されるようになりましたが、これはやや控えめなようですが、基本クラスは以前は各派生クラスで処理されていた初期化を処理するので、提案していただきありがとうございます! –

関連する問題