C# CLR什么时候说对象有终结器?

C# CLR什么时候说对象有终结器?,c#,.net,memory-management,garbage-collection,C#,.net,Memory Management,Garbage Collection,我知道在C语言中,如果您编写~MyClass(),这基本上会转换为覆盖System.Object.Finalize()。因此,无论您是否编写析构函数,CLR中的每个类型都将有一个Finalize()方法(至少是System.Object) 1] 那么,这是否意味着默认情况下,每个对象都有一个终结器 2] CLR决定将对象放入终结队列的依据是什么 我这样问是因为,我有一个类,比如说ManagedResourceHolder,它实现了IDisposable,但没有在其IDisposable.Disp

我知道在C语言中,如果您编写
~MyClass()
,这基本上会转换为
覆盖System.Object.Finalize()
。因此,无论您是否编写析构函数,CLR中的每个类型都将有一个
Finalize()
方法(至少是
System.Object

1] 那么,这是否意味着默认情况下,每个对象都有一个终结器

2] CLR决定将对象放入终结队列的依据是什么

我这样问是因为,我有一个类,比如说
ManagedResourceHolder
,它实现了
IDisposable
,但没有在其
IDisposable.Dispose()方法中调用
GC.SuppressFinalize(this)
。该类不包含任何非托管资源,并且不需要使用
~ManagedResourceHolder()
方法,这反过来意味着不需要使用
GC.SuppressFinalize(this)
调用,因为没有终结器

3] 在上述场景的上下文中,在实现IDisposable时是否总是需要提供终结器?(即使在不包含非托管资源的类上)

FxCop规则让我违反了这一点,当我在CA论坛上询问MSDN时得到的回答让我感到困惑

谢谢

  • 不,这并不意味着这样。只有覆盖的
    Finalize()
    将被CLR计数
  • 通过具有终结器,如上所述
  • 不,并不总是必要的。这只是一个很好的模式。我是说,没有人强迫你这么做。但是,如果您有非托管资源,这是一件好事,因为如果有人忘记处置它,非托管资源将在某个时候被释放。FxCop不执行严格的规则。它强化了良好的模式,如果你不注意这些模式,将来可能会导致失败

  • 更新:每个类都负责管理自己的资源。由于面向对象范例的抽象和封装特性,类的使用者不应该间接地关心它拥有什么资源。因此,您应该手动释放您所拥有的资源(您所拥有的是您直接拥有的,因为您将其他东西视为一个黑盒子),或者将其留给GC来释放它们。对于非托管资源,您没有将其留给GC的选项,因此必须手动释放它。从这个意义上讲,Jon提到的SafeHandle是非托管资源的托管抽象,因此应该将其视为有价值的托管资源(这是一个管理非托管资源本身的终结的黑盒).

    问题1和2:CLR基本上检查终结器是否被覆盖。如果不是,它会将其视为没有终结器

    在System.Object中使用终结器的好处是编译器知道他们总是可以在中调用
    base.Finalize()
    。这避免了版本控制问题。考虑一个没有<代码> Stask.Objult.FielalIZE()/<代码>:

    的世界。
    • System.Object(无最终确定)
    • Acme.BaseClass(无最终确定)
    • MyCompany.DerivedClass(最终确定)
    如果对象中没有
    Finalize
    方法,MyCompany.DerivedClass中的finalizer无法调用任何东西。当Acme.BaseClass的版本2带有终结器时,这会导致一个问题。除非重新编译MyCompany.DerivedClass,否则DerivedClass的实例将在不调用BaseClass.Finalize的情况下完成,这显然是一件坏事

    现在考虑Syr.Objut.FielalIt的相同情况。编译器插入对BASE的调用。在DerivedClass中自动完成Fiel化。Fiel化,在第1版中只调用System.Object中的NOP实现。当Acme.BaseClass的版本2发布时,对

    base.Finalize
    的调用将(不重新编译DerivedClass)调用BaseClass.Finalize

    问题3:不,您不需要仅仅因为实现了IDisposable就拥有终结器。终结器应该只用于非托管资源,其他任何东西都不会清理这些资源,即您直接引用的资源。例如,假设您有一个具有
    FileStream
    成员变量的类。您希望实现
    IDisposable
    ,以便在调用方记得的情况下尽快关闭流,但如果调用方不记得调用
    Dispose()
    ,流将与对象同时符合垃圾收集的条件。相信
    FileStream
    有一个合适的终结器(或使用终结器引用其他内容等),而不是试图在自己的终结器中清理它

    从.NET 2.0开始,使用该类时,您需要自己的终结器的情况应该非常罕见。

    1:只有在被重写时,它才真正起作用(从有用的意义上讲)

    2:如1所定义,且未调用GC.SuppressFinalize(加上重新注册等)

    3:当然不是;事实上,除非您直接处理非托管资源,否则您不应该有终结器。你不应该仅仅因为终结器是IDisposable就添加它,但是有终结器的东西通常也应该是IDisposable的。

    1)是的(通过继承)

    2) 没有任何内容包含对类实例的引用(这将使其有资格进行终结)

    3) 是(为什么要实现IDisposable,除非它要求用户显式调用dispose?在.net中的连接类使用一个隐藏的资源&如果你不调用dispose,它将保留它。由于GC时间未知,连接将保持打开状态,直到那时)

    这是我的理解

    我可能错了。
    在这种情况下,专家们会帮我纠正问题。

    第三点你错了。如果您直接持有非托管资源,则需要一个终结器——但如果您刚刚获得了一个引用t