是否允许终结器调用其他托管类?方法?

发布于 2024-09-01 03:02:22 字数 1405 浏览 3 评论 0原文

我曾经非常确定答案是“否”,如 重写 Finalize 方法对象.最终确定文档

然而,当在 Reflector 中随机浏览 FileStream 时,我发现它实际上可以从终结器中调用这样的方法:

private SafeFileHandle _handle;

~FileStream()
{
    if (this._handle != null)
    {
        this.Dispose(false);
    }
}

protected override void Dispose(bool disposing)
{
    try
    {
        ...
    }
    finally
    {
        if ((this._handle != null) && !this._handle.IsClosed)  // <=== HERE
        {
            this._handle.Dispose();   // <=== AND HERE
        }
        [...]
    }
}

我开始想知道这是否总是有效,因为它的确切编写方式是这样的,因此,“不要接触终结器中的托管类”是否只是一个可以被打破的指导原则,只要有充分的理由和必要的知识就可以正确地做到这一点。

我更深入地挖掘,发现当“规则”被破坏时可能发生的最糟糕的情况是正在访问的托管对象已经被最终确定,或者可能在单独的线程上并行最终确定。因此,如果 SafeFileHandle 的终结器没有执行任何会导致后续调用 Dispose 失败的操作,那么上面的操作应该没问题……对吧?

问题:那么毕竟可能存在这样的情况:另一个托管类上的方法可以从终结器可靠调用吗?我一直认为这是错误的,但这段代码表明这是可能的,并且有足够充分的理由这样做。

奖励:请注意,SafeFileHandle 甚至不知道它是从终结器中调用的,因为这只是对 Dispose() 的正常调用。基类 SafeHandle 实际上有两个私有方法,InternalDisposeInternalFinalize,在本例中 InternalDispose 将称为。这不是问题吗?为什么不呢?...

I used to be pretty sure the answer is "no", as explained in Overriding the Finalize method and Object.Finalize documentation.

However, while randomly browsing through FileStream in Reflector, I found that it can actually call just such a method from a finalizer:

private SafeFileHandle _handle;

~FileStream()
{
    if (this._handle != null)
    {
        this.Dispose(false);
    }
}

protected override void Dispose(bool disposing)
{
    try
    {
        ...
    }
    finally
    {
        if ((this._handle != null) && !this._handle.IsClosed)  // <=== HERE
        {
            this._handle.Dispose();   // <=== AND HERE
        }
        [...]
    }
}

I started wondering whether this will always work due to the exact way in which it's written, and hence whether the "do not touch managed classes from finalizers" is just a guideline that can be broken given a good reason and the necessary knowledge to do it right.

I dug a bit deeper and found out that the worst that can happen when the "rule" is broken is that the managed object being accessed had already been finalized, or may be getting finalized in parallel on a separate thread. So if the SafeFileHandle's finalizer didn't do anything that would cause a subsequent call to Dispose fail then the above should be fine... right?

Question: so there might after all be situations in which a method on another managed class may be called reliably from a finalizer? I've always believed this to be false, but this code suggests that it's possible and that there can be good enough reasons to do it.

Bonus: Observe that the SafeFileHandle will not even know it's being called from a finalizer, since this is just a normal call to Dispose(). The base class, SafeHandle, actually has two private methods, InternalDispose and InternalFinalize, and in this case InternalDispose will be called. Isn't this a problem? Why not?...

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

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

发布评论

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

评论(1

帅气尐潴 2024-09-08 03:02:22

是的,终结器可以调用其他方法。天啊,你甚至可以做一些有趣的事情,例如重新注册类型以进行终结。但是在处理可终结实例时,您必须显式检查 null,因为终结器不能保证以任何顺序运行。

在这种情况下,只需尽可能地关闭事情即可。如果句柄尚未最终确定,那么酷,让我们处理它,否则,终结器已尽力而为。

Yes, finalizers are allowed to call other methods. Hell, you can even do amusing stuff like re-registering types for finalizations, for instance. But you do have to explicitly check for null when dealing with finalizable instances, as finalizers are not guaranteed to run in any order.

In that case it's just a matter of closing things nicely as much as possible. If the handle has not been finalized yet, cool, let's dispose it, otherwise, well, the finalizer did its best.

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