Итак, реализация шаблона удаления по умолчанию выглядит так:
class SomeClass : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = 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) {
// Free any other managed objects here.
}
// Free any unmanaged objects here.
disposed = true;
}
~SomeClass()
{
Dispose(false);
}
}
Говорят, что:
Если вызов метода исходит от финализатора (то есть, если удаление -
false
), выполняется только код, освобождающий неуправляемые ресурсы. Поскольку порядок, в котором сборщик мусора уничтожает управляемые объекты во время завершения, не определен, вызов этойDispose
перегрузки со значениемfalse
предотвращает попытку финализатора освободить управляемые ресурсы, которые, возможно, уже были освобождены.
Возникает вопрос: почему предполагается, что объекты, на которые ссылается объект SomeClass
, возможно, уже были освобождены, и мы не должны пытаться удалить их, когда метод вызывается из финализатора? Если на эти объекты по-прежнему ссылается наш SomeClass
объект, их нельзя освободить, не правда ли? Говорят, что:
Те, у кого есть ожидающие (невыполненные) финализаторы, остаются в живых (на данный момент) и помещаются в специальную очередь. [...] Перед запуском финализатора каждого объекта он еще активен - эта очередь действует как корневой объект.
Итак, опять же, эта очередь ссылается на наш объект SomeClass
(это то же самое, что на него ссылается корень). И другие объекты, на которые есть ссылки на объект SomeClass
, также должны быть активными (поскольку они внедряются через объект SomeClass
). Тогда почему и как они могли быть освобождены к моменту вызова SomeClass
финализатора?