我知道在C#中,如果你写~MyClass()
,这基本上转化为override System.Object.Finalize()
.因此,无论您是否编写析构函数,CLR中的每个类型都会有一个Finalize()
方法(System.Object
至少).
1]那么,这是否意味着,默认情况下,每个对象都有一个终结器?
2] CLR决定一个对象应该通过终结队列的基础是什么?
我问这个,因为,我有一个课,说ManagedResourceHolder
实施IDisposable
,但没有调用GC.SuppressFinalize(this)
它的IDisposable.Dispose()
方法.该类没有任何非托管资源,并且不需要该~ManagedResourceHolder()
方法,这反过来意味着不需要 GC.SuppressFinalize(this)
调用,因为没有终结器.
3]在上述场景的上下文中,在实现IDisposable时是否总是需要提供终结器?(即使在没有非托管资源的类上)
该FxCop的规则CA1816是给我一个违反了这一点,我得到的回应在这里,当我问在MSDN上的CA论坛搞糊涂了.
谢谢.
问题1和2:CLR基本上检查终结器是否被覆盖.如果不是,它会将其视为没有终结器.
在System.Object中使用终结器的好处是编译器知道他们总是可以调用base.Finalize()
.这可以避免版本控制问题.考虑一个没有的世界System.Object.Finalize()
:
System.Object(没有Finalize)
Acme.BaseClass(没有Finalize)
MyCompany.DerivedClass(Finalize)
如果没有Finalize
object中的方法,MyCompany.DerivedClass中的终结器不能调用任何东西.当Acme.BaseClass的第2版带有终结器时会导致问题.除非你重新编译MyCompany.DerivedClass,否则DerivedClass的实例将在不调用BaseClass.Finalize的情况下完成,这显然是一件坏事.
现在考虑与 System.Object.Finalize 相同的情况- 编译器在DerivedClass.Finalize中自动插入对base.Finalize的调用,在版本1中只调用System.Object中的no-op实现.当Acme.BaseClass的第2版出来时,对base.Finalize
will 的调用(不重新编译DerivedClass)调用BaseClass.Finalize.
问题3:不,您不需要因为实现IDisposable而拥有终结器.终结器应仅用于非托管资源,其他任何东西都不会被清理 - 即您可以直接引用的资源.例如,假设您有一个具有FileStream
成员变量的类.您希望实现,IDisposable
以便您可以尽快关闭流,如果调用者记得 - 但如果他们不记得调用Dispose()
,则流将符合与对象同时进行垃圾回收的条件.信任FileStream
具有适当的终结器(或使用终结器等参考其他东西),而不是试图在你自己的终结器中清理它.
从.NET 2.0开始,使用SafeHandle类,您需要自己的终结器应该是非常罕见的.