当你不能在Finalizer/IDisposable上使用SafeHandle时

本文关键字:SafeHandle IDisposable 不能 Finalizer 当你 | 更新日期: 2023-09-27 18:14:16

当看到整个finalizer/IDisposable问题时,通常会看到,在所有冗长的描述之后,最后会有一些"LOL我所说的实际上是无用的,你应该使用SafeHandle来代替再见!"的意思。所以我想知道在什么情况下SafeHandle不适合,这样你就不得不诉诸于终结器/IDisposable旧方式?

当你不能在Finalizer/IDisposable上使用SafeHandle时

显然,当您包装的非托管资源不是通过句柄获取时。这种情况很少见,但并非闻所未闻。一个例子是用c++/CLI代码编写包装器,通常用于包装本地c++类。这个资源就是内存。非托管类型。

然而,你可以花一辈子的时间写托管代码,而永远不要写终结器。终结器属于框架类。

何时不能在Finalizer/IDisposable上使用SafeHandle ?

显而易见的答案是几乎永远不会,safehandle提供了很多优点。

但是ReleasHandle()内部的代码必须确认约束执行区域(Constrained Execution Region, CER)的约束。它不能(不应该)调用可能抛出或锁定的代码。因此,如果你的清理更复杂且"不可靠",你仍然必须使用终结器/析构函数。

但是对于(OS)句柄,您可以并且应该始终使用SafeHandle。

许多类型的非托管资源可以通过在句柄上使用简单的API调用来完成它们的清理职责。这样的资源可以(而且通常应该)有效地封装在SafeHandle中。一些其他类型的非托管资源(例如,由长期发布者持有的事件订阅)具有清理责任,无法通过终结器很好地处理。如果语义上无用的强引用保持被抛弃的对象存活,终结器可能是无用的,并且对于必须由创建它们的线程清理的资源可能是不可用的。没有必要为这些资源编写自定义终结器,因为没有任何类型的终结器可以消除确保它们得到确定性处置的绝对必要性。

然而,某些类型的资源可能会从终结器中受益,即使它们需要做一些在受限执行区域内不允许的事情。当后台线程负责操作对象,并且主应用程序持有一个对象,而该对象又持有对实际对象的引用时,终结器可能会很有用。主应用程序的引用保存对象上的终结器可能会通知后台线程,它所维护的对象不再需要了。这样的信号必须小心地完成,以确保它不会破坏终结器线程,但是如果小心地完成,即使在CER中不允许,它也可能在终结器中有帮助。