2016-09-16 14 views
0

IDisposableオブジェクトの共有所有権を提供するC#クラスがありますか? C++のshared_ptrのようなもの?もしそうでなければ、ここでベストプラクティスは何ですか?C#でIDisposableオブジェクトの共有所有者

UPDATE

私はネイティブのlibを超えるC++/CLIのラッパーを書いています。そして、ネイティブリソース(例えば、MAPI COMインターフェイス)をリリースする必要があります。したがって、を解放してください。

ネイティブ一部:

//Message.h 
class Message 
{ ... }; 

//MessageSet.h 
class MessageSet 
{ 
    ... 
    class iterator : public std::iterator<std::forward_iterator_tag, Message*> 
    { 
    ... 
    public: 
    Message* operator*(); 
    bool operator!=(const iterator& that); 
    iterator& operator++(); 
    }; 
    iterator begin(); 
    iterator end(); 
}; 

マネージド部分(C++/CLI):

public ref class Message 
{ 
    native::Message* inst; 
public: 
    Message(native::Message* inst); 
    ~Message(); 
    !Message(); 
}; 

public ref class MessageSet : public IEnumerable<Message^> 
{ 
    native::MessageSet* inst; 
public: 
    MessageSet(native::Message* inst); 
    ~MessageSet(); 
    !MessageSet(); 
    virtual IEnumerator<Message^>^ GetEnumerator(); 
    virtual System::Collections::IEnumerator^ EnumerableGetEnumerator() = System::Collections::IEnumerable::GetEnumerator; 
}; 

私はメッセージで(多くの同時消費者があるBroadcastBlockブロックすなわち)TPLデータフロー内のオブジェクトを使用しますC#私はこれらのメッセージのDispose()をいつ呼び出すべきかわかりません。

+1

あなたは何を解決しようとしていますか? –

+1

誰が処分を呼びますか?これは、それを行うことができるより高いレベルのオブジェクトです(たとえば、最初にこれらのスレッドを呼び出すもの)。オブジェクトを作成したのは誰ですか?これは、HTTPリクエストや「所有」できる(または所有できるIoCコンテナを持つ)ことができ、このオブジェクトを廃棄することのコンテキストで起こっていますか? –

+2

大きく、大きな違いがあります。 Dispose()の呼び出しはオプションです。オブジェクトの明確な所有権を確立できず、独自の参照カウントスキームを実装する必要がある場合は、単純に呼び出してGCで処理させるほうがずっと優れています。 –

答えて

1

は、私はあなたができる最善のは、このようなものだと思いますそれへの参照。

ここで欠点の1つは、技術的に誰でも共有参照Valueプロパティを使用してアクセスすることで、基礎となる値を処分できることです。あなたは、基礎となる使い捨てタイプを包むが、そのDisposeメソッドを隠す何らかのファサードオブジェクトを作成することによってこれに対処することができます。

+1

OPはこのオブジェクトを複数のスレッド間で共有しようとしており、この実装は複数のスレッドからアクセスされたときには正しく動作しません。共有参照カウントへのアクセスをロックする必要があります。 – Servy

+0

@Servy優れた点。私はマルチスレッド要件を見逃していました。 – Kyle

0

これはいいえ。 私が今までに見つけた最良の方法は、DictionariesとWeakReferencesを使用して、非常にclunkyです。ディクショナリはオブジェクトを参照カウントします。弱参照は人工的に参照カウントを増加させないように使用されます。

-1

あなたは自身IDisposable、あなたはそれは、そう.NET Garbage Collectorが起こった事実について通知し、あなたのクラスでオーバーライドされたメソッドを呼び出しますを実装ません。

shared_ptrとは異なる概念です。デストラクタはで、ポインタの最後の所有権がなくなるとが呼び出されることが保証されています。一般的に

は、.NETで、あなたはunsafeプログラミング技術を使用していない場合を除き、あなたは自身何もしない、.NET Garbage Collectorはそれを所有しています。 オブジェクトを明示的に破棄しても、割り当てられたメモリは、C++のように即座に再利用されることはなく、しばしば再利用されません。

EDIT

あなたがネイティブリソースを持っており、正確な瞬間にそれらを解放したい場合は、それを達成することができますによって:

1)あなたの.NETラッパーオブジェクトでIDisposableを実装

2)その内側のDispose()のメソッドは、リリースするコードを書きますネイティブリソース

3)ラッパーオブジェクトを使用するコードでは、のネイティブリソースをラッパーオブジェクトによって割り当てたい場合は、明示的にDispose()を呼び出してください。

この場合、Dispose()メソッドが呼び出され、コードが実行され、すぐにネイティブリソースが解放されます。その後

EDIT(2)

についての質問です何より明確である:あなたがDispose()が呼び出さなければならないとき、私はハンスさんのコメント@にとどまると判断できない場合は

:ちょうどリレー最終的に(すぐにまたはそれ以降)GCを呼び出し、独自の参照カウンタの実装を避けてください(特にマルチスレッド環境では)。 あなたの状況で実現可能であれば、ホイールを発明しないでください。

public sealed class SharedDisposable<T> where T : IDisposable 
{ 
    public sealed class Reference : IDisposable 
    { 
     public Reference(SharedDisposable<T> owner) 
     { 
      mOwner = owner; 
     } 

     public void Dispose() 
     { 
      if(mIsDisposed) return; 
      mIsDisposed = true; 

      mOwner.Release(); 
     } 

     public T Value => mOwner.mValue; 

     private readonly SharedDisposable<T> mOwner; 
     private bool mIsDisposed; 
    } 

    public SharedDisposable(T value) 
    { 
     mValue = value; 
    } 

    public Reference Acquire() 
    { 
     lock(mLock) 
     { 
      if(mRefCount < 0) throw new ObjectDisposedException(typeof(T).FullName); 
      mRefCount++; 
      return new Reference(this); 
     } 
    } 

    private void Release() 
    { 
     lock(mLock) 
     { 
      mRefCount--; 
      if(mRefCount <= 0) 
      { 
       mValue.Dispose(); 
       mRefCount = -1; 
      } 
     } 
    } 

    private readonly T mValue; 
    private readonly object mLock = new object(); 
    private int mRefCount; 
} 

基本的にこれを使用すると、1つのオブジェクト(SharedDisposable<T>)配布「共有」するためのメカニズムを提供しながら、基本的な使い捨ての寿命を管理を持つことができます:

+3

クラスはIDisposableを所有しておらず、実装することができます。しかし、インスタンスはIDisposableを実装できる別のインスタンスの所有者であることは間違いありません。 A型のインスタンスがFileStreamを使用する場合、インスタンスはそのFileStreamインスタンスを所有し、そのインスタンスを破棄しなければなりません。 – Maarten

+0

@Maarten:私はメモリ割り当て/レクラメーションの所有権について話しています(つまり、shared_ptrについてです)。あなたは.NETで何も所有していないので、 'null'に設定することでインスタンスを"削除 "できますが、' GC'がそうしない限り、インスタンスのメモリや割り当てられたリソースを解放しません。 – Tigran

+2

Maartenのポイントに追加するには、ディスポーザブルの*目的*は、そのリソースの決定的な処分を提供することです*。あなたは*それをGCに任せるわけではありません。 'IDisposable'は、GC *によって管理されていないリソースをクリーンアップするために存在します。あなたがオブジェクトに 'Dispose'を呼び出すと、それは即座に処理され、確定的に*処理されます。 – Servy