我可以检测对象是否已调用GC.SuppressFinalize吗?

时间:2011-01-08 15:50:09

标签: c# .net finalizer

有没有办法检测对象是否已调用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有方法设置对象的可终结性(SuppressFinalizeReRegisterForFinalize),但我没有看到获取的任何方法对象的可终结性。有没有办法查询是否已在给定的实例上调用GC.SuppressFinalize,还没有购买Typemock或编写我自己的CLR主机?

3 个答案:

答案 0 :(得分:4)

这是不可能的,GC只是不提供此信息。很好的理由,对象可能不仅仅是两个状态。它也可能已经在最终确定队列中,或者它可能已经完成。

自定义CLR主机无法帮助您,托管接口不会向gc提供任何挂钩。你可以通过在终结器中检查它来检查是否已经调用了SuppressFinalize。记录(快速)。你无法证明相反的情况。

Fwiw,.NET框架类没有这样做,他们只是让终结器运行。

答案 1 :(得分:3)

如果您想确认如果您的对象不拥有该资源已经取消了最终确定,那么也许您可以让终结器断言它拥有该资源?测试必须执行GC.Collect和GC.WaitForPendingFinalizers,但是生产代码除了断言之外没有任何额外的东西(可以从生产构建中省略)。断言的一个小问题是:如果创建对象的线程在创建对象和设置所有权状态之间死亡,则终结器可能运行不当。

有人说过,我想知道拥有一个抽象的ResourceWrapper类型是否更好,它具有独立的子类型OwnedResourceWrapper和SharedResourceWrapper,它们拥有或不拥有相关资源。然后,不拥有资源的子类型首先不需要终结器。请注意,SharedResourceWrapper将IDisposable实现为无操作可能很有用。

答案 2 :(得分:2)

这可能会有所帮助(减少荒谬)。一个技巧是在终结器中做一些日志(这可能是一个静态),如果有人不在,他已经调用了压制最终确定,但你仍然无法确定何时。

如果您是该类型的作者,则此功能正常。