繁体   English   中英

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

[英]When does CLR say that an object has a finalizer?

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

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

2] CLR决定一个对象应该通过终结队列的基础是什么?

我问这个,因为,我有一个类,说ManagedResourceHolder实现了IDisposable ,但没有在其IDisposable.Dispose()方法中调用GC.SuppressFinalize(this) 该类没有任何非托管资源,并且不需要~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方法,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的调用将(无需重新编译DerivedClass)调用BaseClass.Finalize。

问题3 :不,您不需要因为实现IDisposable而拥有终结器。 终结器应仅用于非托管资源, 其他任何东西都不会被清理 - 即您可以直接引用的资源。 例如,假设您有一个具有FileStream成员变量的类。 您希望实现IDisposable以便您可以尽快关闭流,如果调用者记得 - 但如果他们记得调用Dispose() ,则该流将有资格与您的对象同时进行垃圾回收。 相信FileStream有一个合适的终结器(或者使用终结器等对其他东西的引用),而不是试图在你自己的终结器中清理它。

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

1:它只是被重写(在有用的意义上)

2:由1定义,并且没有调用GC.SuppressFinalize(加上重新注册等)

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

  1. 不,这并不意味着。 只有被覆盖的Finalize()才会被CLR计算。
  2. 通过具有如上定义的终结器。
  3. 不,这并不总是必要的。 这只是一个很好的模式。 我的意思是,没有人强迫你这样做。 但是,如果你有非托管资源,这是一件好事,因为如果有人忘记处理它,非托管资源将在某个时候被释放。 FxCop不强制执行严格的规则。 如果您不照顾,它会强制执行可能导致将来失败的良好模式。

更新:每个班级都负责管理自己的资源。 由于面向对象范例的抽象和封装特性,类的消费者不应该间接关注它拥有的资源。 因此,您应该手动释放您拥有的资源(您拥有的是您在将其他东西视为黑盒时 直接拥有的资源)或将其留给GC以释放它们。 对于非托管资源,您无法将其保留到GC,因此必须手动释放它。 从这个意义上讲,Jon提到的SafeHandle是非托管资源托管抽象 ,因此它应被视为有价值的托管资源(这是一个黑盒子,用于管理非托管资源本身的最终化)。

1)是(凭借继承)

2)没有任何东西持有对类实例的引用(这将使其有资格完成)

3)是(为什么一个人应该实现IDisposable,除非它要求用户明确地调用dispose?.net中的连接类使用一个非管理资源并且如果你不调用dispose,它将依赖它。由于GC时间未知,连接将保持打开,直到那个时间)

这是我的理解。

我错了。 在这种情况下,专家会为我纠正问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM