c#中可分配对象的共享所有权

本文关键字:共享 所有权 对象 可分配 | 更新日期: 2023-09-27 18:07:25

c#中是否有提供可分配对象的共享所有权的类?c++中的shared_ptr之类的东西?如果没有,这里的最佳实践是什么?

我在native 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#中使用TPL数据流(BroadcastBlock块,即有许多并发消费者)中的消息对象时,我不知道何时应该为这些消息调用Dispose()

c#中可分配对象的共享所有权

我认为你最好这样做:

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>)管理底层一次性对象的生命周期,同时提供一种机制来分发对它的"共享"引用。

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

那将是NO。到目前为止,我发现最好的方法是使用字典和WeakReferences,这相当笨拙。Dictionary将对象映射到它的refcount。使用WeakReference是为了避免人为地增加引用计数。

你不拥有 IDisposable,你实现它,所以。net垃圾收集器将调用重写的方法在你的类,通知发生了一个事实。

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

一般来说,在。net中,除非您不使用不安全的编程技术,否则您不拥有任何东西,是。net垃圾收集器拥有的。即使在显式地销毁对象时,为它分配的内存也可能不会,而且通常不会立即回收,就像C++所期望的那样。

编辑

如果您有本地资源并希望在精确的时刻释放它们,可以通过以下方式实现:

1)用。net包装器对象实现IDisposable

2)在该包装器的Dispose()方法中编写释放本地资源的代码

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

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

EDIT (2)

之后问题就更清楚了:

如果你不能确定什么时候必须调用Dispose(),我会坚持@Hans的评论:只是中继最终(迟早)GC调用,避免你自己的引用计数器实现(特别是在多线程环境中)。如果在你的情况下可行的话,就不要白费力气了。