C#中IDisposable对象的共享所有权

时间:2016-09-16 13:16:09

标签: c# shared-ptr idisposable

C#中是否有提供IDisposable对象共享所有权的类?像c ++中的shared_ptr?如果没有,这里的最佳做法是什么?

更新

我在本机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;
};

当我在C#中使用Message对象(BroadcastBlock块,即有许多并发消费者)时,我不知道何时应该为这些消息调用Dispose()。

3 个答案:

答案 0 :(得分:1)

我认为你能做的最好就是这样:

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;
}

基本上,这允许您让一个对象(SharedDisposable<T>)管理底层一次性用品的生命周期,同时提供一种机制来分发&#34;共享&#34;引用它。

这里的一个缺点是技术上任何人都可以通过共享引用Value属性访问它来处置基础值。您可以通过创建某种外观对象来解决这个问题,该对象包装了底层的一次性类型,但隐藏了它的Dispose方法。

答案 1 :(得分:0)

那不会。 到目前为止,我发现的最好方法是使用Dictionaries和WeakReferences非常笨重。 Dictionary将对象映射到它的引用计数。使用WeakReference,因此您不会人为地增加引用计数。

答案 2 :(得分:-1)

拥有 IDisposable实施,因此.NET Garbage Collector会在您的课程中调用重写方法,通知发生的事实。

这是与shared_ptr不同的概念,其中析构函数保证在指针的最后一个所有权消失后被调用。

通常,在.NET中,除非您没有使用unsafe编程技术,否则拥有任何内容,.NET Garbage Collector拥有它。 即使你明确地销毁了一个对象,分配给它的内存也许不会,也常常不会被立即回收,就像曾经期望C++一样。

编辑

如果您有本机资源并希望在精确时刻发布它们,那么可以通过以下方式实现:

1)使用.NET包装器对象实现IDisposable

2)该包装器的Dispose()内部方法编写释放原生资源的代码

3)在使用包装器对象的代码中,当你想要释放由包装器对象分配的 native 资源时,在其上显式调用Dispose()

在这种情况下调用Dispose()方法,您的代码会立即执行并释放本机资源

编辑(2)

之后更清楚的是什么问题:

如果您无法确定何时需要调用Dispose(),我会留在@Hans的评论中:只是转发最终(很快或稍后)GC电话并避免您自己的参考计数器实施(特别是在多线程环境中)。 如果在您的情况下这是可行的,请不要发明轮子。