C# 关于C中的Dispose模式和终结器#

C# 关于C中的Dispose模式和终结器#,c#,destructor,dispose,finalizer,C#,Destructor,Dispose,Finalizer,先进的 有一个标准的Dispose模式。还有一个bool作为protectedDispose方法的参数,告诉GC是否已经手动释放了托管资源,这样GC就不需要关心它们了 现在的问题是,在if(disposing){}块中应该做什么?通常GC会清理托管资源,因此不需要做任何特殊的事情。但是由于在这个块中,需要显式地清理托管资源,这是否意味着只需将对象中的所有字段和内容设置为null 其次,在语言中只有一个析构函数(或终结器,不管它调用什么)不是更好吗?然后在GC设计中,只需输入一点来确定析构函数是否

先进的

有一个标准的Dispose模式。还有一个bool作为protected
Dispose
方法的参数,告诉GC是否已经手动释放了托管资源,这样GC就不需要关心它们了

现在的问题是,在
if(disposing){}
块中应该做什么?通常GC会清理托管资源,因此不需要做任何特殊的事情。但是由于在这个块中,需要显式地清理托管资源,这是否意味着只需将对象中的所有字段和内容设置为
null

其次,在语言中只有一个析构函数(或终结器,不管它调用什么)不是更好吗?然后在GC设计中,只需输入一点来确定析构函数是否已经被调用,这样就不需要对其进行垃圾收集,或者析构函数尚未被调用,GC应该清理它。我发现Dispose模式非常复杂,我非常困惑在哪个函数中清理什么,以及如何在派生类中清理。通过使用单析构函数设计,GC只是在还没有清理的时候清理,而在已经清理的时候不清理

问候

PS:那么,这也是一种很好且更简单的清理对象的模式吗

class Foo
{
    bool unmanagedDisposed = false;
    void Dispose() {/*clean up unmanaged resources*/ unmanagedDisposed = true;}
    ~Foo() {if (!unmanagedDisposed) Dispose();}
}
因此,如果程序员知道并记得调用
Dispose()
,则在终结器中无需执行任何操作,否则将清理终结器中的非托管资源。在这里,我们不需要关心那些被管理的资源

if(disposing){}
块中应该做什么

清理托管资源,即在此时对所有IDisposable对象调用
Dispose()

要显式清理托管资源,是否意味着只需将对象中的所有字段和内容设置为null

不,这并不意味着。这只是关于可识别的对象

语言中只有一个析构函数(或终结器,不管它调用什么)不是更好吗

我们只有一个析构函数,也就是终结器,
Dispose()
不是。这使得你这一段的其余部分无关紧要


我们有一次性模式和GC,它们是相关的和合作的,但并不相同。GC管理内存,并且只管理内存。IDisposable用于管理资源(流、连接、位图)。

基本上,如果您有一个具有非托管字段或属性的类,则只需要使用dispose实现完整的
~Destructor()
模式

如果您的所有字段和属性都是托管的,而不是一次性的,那么您根本不需要实现IDisposable

如果您的某个字段或属性是一次性的,那么您只需要实现IDisposable模式。你不必完全按照上面的模式

如果在最后一种情况下,字段或属性中确实存在非托管资源(例如,指向某个对象的本机指针、ADO以外的数据库连接或其他托管连接),则.net不知道如何在垃圾收集器运行时清理它

在这种情况下,需要考虑两个对象清理的地方。要么由开发人员调用
Dispose()
像他应该做的那样对其进行清理,要么他会忘记。如果他忘记了,而你有一个析构函数,那么它就会被放到一个终结队列中

这就是调用
Dispose(disposing)
的地方。 如果开发人员很好,并且调用了
Dispose()
,那么您可以发送true,以便也可以清理托管资源


如果开发人员没有调用dispose,而较差的对象最终出现在终结队列中,那么对托管对象调用
dispose()
将引发异常,因为它们不再存在。因此,在本例中,您将发送一个False,以便跳过托管资源并避免异常。我不确定这一点,但传说在终结队列中抛出异常会退出整个过程,甚至可能导致世界末日。所以不要这样做。

我总是发现空值与处置想法相当,这是一个任何人都会接受的奇怪结论intuition@henk-霍特曼感谢您对
if(disposing){}
块的具体说明!无论如何,我所说的析构函数或终结器是指将所有的销毁例程放在一起,这样就不需要关心终结器和dispose接口。我仍然需要通过我的onw.Caveat“如果您的某个字段或属性是一次性的…”一段来明确这一点-如果类不是密封的(不幸的是,不是默认的),并且您正在实现一次性的,你应该全力以赴,因为你不知道派生类需要什么或做什么。@MiketheTike谢谢你的清晰答案,在阅读了你的答案后,我确实有了更好的理解。因此,我认为终结器只是确保无论程序员是否调用
Dispose
清理非托管资源。而且,由于我们还可以将托管资源与非托管资源一起清理,因此我们需要分别处理
Dispose
和终结器中的托管资源。@Damien_不相信者:这是微软在第一次编写
Dispose
模式时的想法。然而,在实践中,如果基类不封装任何非托管资源,则派生类也不应该封装。他们可能需要的任何非托管资源都应该封装在他们自己的可终结类(可能嵌套在派生类中)中,派生类随后可以将其用作托管资源。阅读这篇伟大的文章以完全理解Dispose模式。第一次阅读时非常复杂,但非常有启发性。假设您的一个类托管资源本身实现了
IDisposable
。你在哪里