1

以下是来自以下来源的代码: https ://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose

using System;

class BaseClass : IDisposable
{
    // To detect redundant calls
    private bool _disposed = false;

    ~BaseClass() => Dispose(false);

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
        {
            return;
        }

        if (disposing)
        {
            // TODO: dispose managed state (managed objects).
        }

        // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
        // TODO: set large fields to null.

        _disposed = true;
    }
}

消息来源说了为什么

if (disposing) {
   // TODO: dispose managed state (managed objects).
}

需要:

如果方法调用来自终结器,则只有释放非托管资源的代码应该执行。实现者负责确保错误路径不会与可能已被回收的托管对象交互。这很重要,因为垃圾收集器在终结期间销毁托管对象的顺序是不确定的。

但是我有一个问题,当 BaseClass 的 Finalize 方法被调用时,它所有包含托管对象的字段仍将在堆中,因为 BaseClass 对象本身必须在垃圾收集中幸存下来并被提示到另一代,并且当可终结对象得到提升时,其字段引用的任何对象也会得到提升,因为它们也必须继续存在。
所以BaseClass的字段引用的托管对象不会被GC回收。任何人都可以提供一个具体的例子,为什么它需要以这种方式实现?

4

1 回答 1

4

如果您在终结器中(而不是Dispose()) - 即disposingis ,您根本false不应该假设其他对象的状态。您不知道终结器将以什么顺序执行。没有确定的顺序,也无法提供(想想“循环”)。此外:这不是重点。如果你想清理托管资源,你应该在. 如果有人没有打电话,那么那个人有一个错误,而不是你。您应该只与终结器中的非托管资源对话。坦率地说,访问真正不受管理的资源是令人难以置信的Dispose()Dispose()很少见,所以在现实中:您几乎不需要任何这种复杂性。

于 2021-04-09T08:31:19.747 回答