3

有没有办法检测一个对象是否调用了 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 主机?

4

3 回答 3

4

这是不可能的,GC 只是不提供此信息。这样做的充分理由是,对象不仅可以处于两种状态。它也可能已经在终结队列中,或者它可能已经被终结。

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

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

于 2011-01-08T16:16:49.343 回答
3

如果您想确认在您的对象不拥有资源的情况下已抑制终结,也许您可​​以让终结器断言它拥有资源?测试必须执行 GC.Collect 和 GC.WaitForPendingFinalizers,但生产代码除了断言(可以从生产构建中省略)之外没有任何额外内容。断言的一个小警告:如果创建对象的线程在创建对象和设置所有权状态之间死亡,则终结器可能会不适当地运行。

话虽如此,我想知道拥有或不拥有相关资源的抽象 ResourceWrapper 类型是否更好,该类型具有单独的子类型 OwnedResourceWrapper 和 SharedResourceWrapper。然后,不拥有资源的子类型首先不需要终结器。请注意,SharedResourceWrapper 将 IDisposable 实现为无操作可能很有用。

于 2011-01-13T15:39:26.770 回答
2

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

如果您是该类型的作者,这将起作用。

于 2011-01-08T16:22:14.930 回答