有没有办法检测对象是否已调用GC.SuppressFinalize?
我有一个看起来像这样的对象(为了清晰起见,完全展开的Dispose模式):
public class ResourceWrapper {
private readonly bool _ownsResource;
private readonly UnmanagedResource _resource;
public ResourceWrapper(UnmanagedResource resource, bool ownsResource) {
_resource = resource;
_ownsResource = ownsResource;
if (!ownsResource)
GC.SuppressFinalize(this);
}
~ResourceWrapper() {
if (_ownsResource)
// clean up the unmanaged resource
}
}
如果ownsResource
构造函数参数是false
,那么终结器将无所事事 - 所以从构造函数中调用GC.SuppressFinalize
似乎是合理的(如果有点古怪) 。但是,因为这种行为很古怪,我很想在XML文档注释中注意到它...如果我想对它进行评论,那么我应该为它编写一个单元测试。
虽然System.GC有方法设置对象的可终结性(SuppressFinalize,ReRegisterForFinalize),但我没有看到获取的任何方法对象的可终结性。有没有办法查询是否已在给定的实例上调用GC.SuppressFinalize,还没有购买Typemock或编写我自己的CLR主机?
答案 0 :(得分:4)
这是不可能的,GC只是不提供此信息。很好的理由,对象可能不仅仅是两个状态。它也可能已经在最终确定队列中,或者它可能已经完成。
自定义CLR主机无法帮助您,托管接口不会向gc提供任何挂钩。你可以通过在终结器中检查它来检查是否已经调用了SuppressFinalize。记录(快速)。你无法证明相反的情况。
Fwiw,.NET框架类没有这样做,他们只是让终结器运行。
答案 1 :(得分:3)
如果您想确认如果您的对象不拥有该资源已经取消了最终确定,那么也许您可以让终结器断言它拥有该资源?测试必须执行GC.Collect和GC.WaitForPendingFinalizers,但是生产代码除了断言之外没有任何额外的东西(可以从生产构建中省略)。断言的一个小问题是:如果创建对象的线程在创建对象和设置所有权状态之间死亡,则终结器可能运行不当。
有人说过,我想知道拥有一个抽象的ResourceWrapper类型是否更好,它具有独立的子类型OwnedResourceWrapper和SharedResourceWrapper,它们拥有或不拥有相关资源。然后,不拥有资源的子类型首先不需要终结器。请注意,SharedResourceWrapper将IDisposable实现为无操作可能很有用。
答案 2 :(得分:2)
这可能会有所帮助(减少荒谬)。一个技巧是在终结器中做一些日志(这可能是一个静态),如果有人不在,他已经调用了压制最终确定,但你仍然无法确定何时。
如果您是该类型的作者,则此功能正常。