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

发布于 2024-10-11 00:44:33 字数 1247 浏览 3 评论 0原文

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

Is there a way to detect whether or not an object has called GC.SuppressFinalize?

I have an object that looks something like this (full-blown Dispose pattern elided for clarity):

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
    }
}

If the ownsResource constructor parameter is false, then the finalizer will have nothing to do -- so it seems reasonable (if a bit quirky) to call GC.SuppressFinalize right from the constructor. However, because this behavior is quirky, I'm very tempted to note it in an XML doc comment... and if I'm tempted to comment it, then I ought to write a unit test for it.

But while System.GC has methods to set an object's finalizability (SuppressFinalize, ReRegisterForFinalize), I don't see any methods to get an object's finalizability. Is there any way to query whether GC.SuppressFinalize has been called on a given instance, short of buying Typemock or writing my own CLR host?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

橘和柠 2024-10-18 00:44:33

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

自定义 CLR 主机不会帮助您解决此问题,托管接口不提供任何与 gc 的挂钩。您可以通过在终结器中检查 SuppressFinalize 来检查 SuppressFinalize 是否在应该调用时被调用。 (快速)记录下来。你无法证明相反的情况。

Fwiw,.NET 框架类不会执行此操作,它们只是让终结器运行。

This is not possible, the GC just doesn't provide this information. Good reason for that, it isn't just two states that the object can be in. It also might already be on the finalization queue or it might already have been finalized.

A custom CLR host isn't going to help you with that, the hosting interface don't provide any hooks into the gc. You can check if SuppressFinalize has been called when it should have simply by checking this in the finalizer. Log it (quickly). You can't prove the opposite.

Fwiw, the .NET frame classes don't do this, they just let the finalizer run anyway.

遗心遗梦遗幸福 2024-10-18 00:44:33

如果您想确认如果您的对象不拥有该资源,则终结已被抑制,也许您可​​以让终结器断言它拥有该资源?测试必须执行 GC.Collect 和 GC.WaitForPendingFinalizers,但生产代码除了断言之外不会有任何额外的东西(可以从生产构建中省略)。关于断言的一个小警告:如果创建对象的线程在创建对象和设置所有权状态之间终止,则终结器可能无法正常运行。

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

If you want to confirm that finalization has been suppressed if your object doesn't own the resource, perhaps you could have the finalizer assert that it owns the resource? The test would have to do GC.Collect and GC.WaitForPendingFinalizers, but production code wouldn't have anything extra except the assert (which could be omitted from the production build). One slight caveat with the assert: if the thread that creates the object dies between creating the object and setting the ownership status, the finalizer may run inappropriately.

That having been said, I wonder whether it would be better to have an abstract ResourceWrapper type, with separate subtypes OwnedResourceWrapper and SharedResourceWrapper, that own or do not own the resource in question. Then the subtype that doesn't own resources wouldn't need to have a finalizer in the first place. Note that it may be useful for SharedResourceWrapper to implement IDisposable as a no-op.

孤单情人 2024-10-18 00:44:33

这可能会有所帮助(归谬法)。一个技巧是在终结器中做一些日志(这可能是静态状态),如果有人缺席,他已经调用了抑制终结器,但您仍然无法确定何时。

如果您是该类型的作者,则此方法有效。

This may help (reductio absurdum). A trick would be do some log (this could be a static state) in finalizers and if somebody is absent, he has called the suppress finalize but still you cannot be sure when.

This is working if you are the author of the type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文