C# CLR什么时候说对象有终结器?
我知道在C语言中,如果您编写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
~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