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()
我认为你最好这样做:
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
Dispose()
方法中编写释放本地资源的代码
3)在使用包装器对象的代码中,当您想要释放由包装器对象分配的本机资源时,对其显式调用Dispose()
。
Dispose()
方法,您的代码执行并立即释放本地资源。EDIT (2)
之后问题就更清楚了:
如果你不能确定什么时候必须调用Dispose()
,我会坚持@Hans的评论:只是中继最终(迟早)GC
调用,避免你自己的引用计数器实现(特别是在多线程环境中)。如果在你的情况下可行的话,就不要白费力气了。