在c#中,我们可以使用finalize来处理托管源吗

本文关键字:处理 finalize 我们 可以使 | 更新日期: 2023-09-27 18:21:51

根据如何使用IDisposable的模式,Microsoft建议使用finalize来释放非托管源。http://msdn.microsoft.com/en-us/library/system.idisposable%28v=VS.80%29.aspx

但是,如果我们在finalize中编写一些代码来发布托管源代码,会发生什么呢?也就是说,当GC调用最终确定释放某个托管源时,会发生什么?

在c#中,我们可以使用finalize来处理托管源吗

这通常是一种糟糕的做法。在终结器代码中,您不能依赖对象及其托管资源的状态——它们可以已经被收集或处理/终结。此外,您不能依赖CLR调用Finalize的顺序。

通常,使用Finalize清理外部托管资源是无用的,而且可能很危险。当对象终结器运行时,它所拥有的托管资源可能是:

  1. 由于运行了终结器,已经清理完毕,在这种情况下,处理它们将毫无用处。
  2. 尚未清理,但被识别为未被任何活动对象引用,在这种情况下,无论当前执行的终结器是否试图清理它们,它们的终结器都将在适当的时候运行。
  3. 仍在被其他活动对象使用,在这种情况下,当前运行的终结器不应该清理它们。

在某些情况下,让终结器对其他托管对象调用清理代码可能会有所帮助,但这种调用通常只适用于对象了解彼此内部详细信息的情况,通常应使用protectedinternal方法或使用私人交换的委托来执行。例如,在某些情况下,可能有两个或多个相互了解的对象,并且具有必须按特定顺序运行的终结器。

例如,可能存在一个类,其目的是向USB设备发送数据,而另一个类的目的是控制连接到该设备的设备。如果后一类想要确保设备接收到"关闭"命令,则可能需要其终结器在USB连接类终结器关闭连接之前发送该命令。处理这一问题的最干净的方法可能是让USB连接对象的构造函数接受回调,它将从其终结器调用该回调。如果这个类没有这样的功能,事情可能会很糟糕。另一种方法可以是使一个与包装器分离的对象,该对象保存清理所需的所有信息,以及包装器对象的WeakReference,并且具有计时器滴答事件,如果WeakReference失效,则计时器滴答事件将执行清理。如果计时器绑定到创建包装对象的线程,那么即使包装对象被放弃,也可以执行清理,前提是线程仍然存在(如果线程不存在,事情会变得更复杂)。

为什么(或者更好的是,如何)发布在终结器中管理的东西?当前对象拥有的所有内容此时都已被视为垃圾,并将在垃圾收集器的下一次运行中进行收集。当前所做的而不是拥有的一切都无法发布,因为其他东西可能仍然引用它。

不需要为托管代码编写Dispose/Finalize。bcz当不再引用对象时,CLR将删除它。Dispose方法是为非托管代码(如文件处理程序或数据库命令)编写的。