有一个标准的Dispose模式。并且有一个bool作为受保护Dispose
方法的参数,告诉GC是否已经手动释放了托管资源,因此GC不需要关心它们。
现在的问题是,在if (disposing) {}
区块内究竟应该做些什么?通常,GC会清理托管资源,因此无需执行任何特殊操作。但是因为在这个块中,需要明确清理托管资源,这是否意味着只需将对象中的所有字段和内容设置为null
?
其次,在语言中只有一个析构函数(或者它所调用的终结函数)是不是更好?然后在GC设计中,只需稍微确定是否已经调用了析构函数,这样就不需要对其进行垃圾收集,或者还没有调用析构函数,GC应该清理它。我发现Dispose模式非常复杂,我很困惑要清理哪些函数以及如何清理派生类。通过使用signle析构函数设计,GC只是在它们尚未清理时清理它们,并且当它们已经清理时它们不会清理。
问候
PS:这也是清理对象的一个好而简单的模式吗?
class Foo
{
bool unmanagedDisposed = false;
void Dispose() {/*clean up unmanaged resources*/ unmanagedDisposed = true;}
~Foo() {if (!unmanagedDisposed) Dispose();}
}
因此,如果程序员知道并记得调用Dispose()
,则无法在终结器中执行任何操作,否则将清除终结器中的非托管资源。在这里,我们不需要关心那些托管资源。
答案 0 :(得分:1)
在
if (disposing) {}
区块内应该做什么?
您清理托管的资源,即您在此时拥有的所有IDisposable对象上调用Dispose()
。
显式清理托管资源,这是否只是将对象中的所有字段和内容设置为null?
不,这并不意味着。它只与IDisposable对象有关。
在语言中只有一个析构函数(或者它所调用的终结函数)不是更好吗?
我们只有一个析构函数,即Finalizer,而Dispose()
不是它。这使得你的段落的其余部分无关紧要。
我们有一次性模式和GC,它们是相关的,合作但不一样。 GC管理内存和仅内存。 IDisposable用于管理资源(流,连接,位图)。
答案 1 :(得分:1)
基本上,如果您的类具有非托管字段或属性,则只需要使用dispose实现完整的~Destructor()
模式。
如果您管理的所有字段和属性都不是一次性的,那么您根本不需要实现IDisposable。
如果您的某个字段或属性是一次性的,那么您需要实现IDisposable模式。你不一定要用上面的模式来养猪。
如果在最后一种情况下你在一个字段或属性中有一个非托管资源(例如一个指向某个东西的本机指针,一个除ADO或其他托管连接之外的数据库连接),那么.net不知道如何清理它垃圾收集器四处滚动。
在这种情况下,您需要考虑清理对象的两个位置。开发人员会像他应该的那样打电话给Dispose()
来清理它,或者他会忘记。如果他忘记了,并且你有一个析构函数,那么它就会被置于一个终结队列中。
这是Dispose(disposing)
来电的地方。
如果开发人员很好并且调用了Dispose()
,那么您发送的是true,以便也可以清理托管资源。
如果开发人员没有调用dispose并且穷人对象最终在终结队列上,那么在托管对象上调用Dispose()
将抛出异常,因为它们不再存在。因此,在这种情况下,您发送一个False,以便跳过托管资源并避免异常。我不确定这一点,但是传说说在终结队列上抛出异常会退出整个过程,甚至可能会结束这个世界。所以不要这样做。