Два вопроса о Dispose () и деструкторах в C # - PullRequest
16 голосов
/ 06 января 2011

У меня вопрос о том, как использовать Dispose() и деструкторы.Читая некоторые статьи и документацию MSDN , кажется, это рекомендуемый способ реализации Dispose() и деструкторов.

Но у меня есть два вопроса об этой реализации, которые вы можете прочитать ниже:

class Testing : IDisposable
{
    bool _disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed) // only dispose once!
        {
            if (disposing)
            {
                // Not in destructor, OK to reference other objects
            }
            // perform cleanup for this object
        }
        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);

        // tell the GC not to finalize
        GC.SuppressFinalize(this);
    }

    ~Testing()
    {
        Dispose(false);
    }
}

GC.SupressFinalize (this) для Dispose ()

Когда программист используетusing или вызывает Dispose () explicity, наш класс вызывает GC.SupressFinalize(this).Мой вопрос здесь:

  • Что именно это означает?Будет ли объект собираться, но без вызова деструктора?Я предполагаю, что ответ положительный, поскольку деструкторы конвертируются платформой в вызов Finalize (), но я не уверен.

Финализация без вызова Dispose ()

Предположим, что GC собирается очистить наш объект, но программист не вызвал Dispose()

  • Почему мы не располагаем ресурсом в этот момент?Другими словами, почему мы не можем освободить ресурсы для деструктора?
  • Какой код должен быть выполнен внутри if и снаружи?

    if (!_disposed) // only dispose once!
    {
       if (disposing)
       {
           //What should I do here and why?
       }
       // And what here and why?
    }
    

Спасибо заранее

Ответы [ 3 ]

13 голосов
/ 06 января 2011

1.Что делает SuppressFinalize?

Он отменяет регистрацию объекта в списке финализатора, т.е. когда GC позднее собирает объект, он игнорирует присутствие деструктора.Это большой выигрыш в производительности, так как в противном случае деструктор потребовал бы задержки объекта коллекции и всего, на что он ссылается.

2.Почему мы не располагаем [управляемым] ресурсом на этом этапе?Другими словами, почему мы не можем освободить [управляемые] ресурсы с помощью деструктора?

Можно, но это точно бессмысленно: объект, в котором вы находитесь, стал недоступным, поэтому все принадлежащие им управляемые ресурсытоже недостижим.Они будут финализированы и собраны GC в том же прогоне, и вызов Dispose () для них не нужен, но не полностью без риска или затрат.

2a Какой код должен выполняться в if внутри,и что за пределами?

Внутри if(disposing), вызовите _myField.Dispose()

Другими словами, Утилизируйте управляемых ресурсов (объекты с Dispose)

Снаружи, вызовите код для очистки (закрытия) неуправляемых ресурсов, таких как Win32API.Close(_myHandle).

Обратите внимание, что когда у вас нет неуправляемых ресурсов, как это обычно бываетслучай (ищите SafeHandle), вам не нужен деструктор и, следовательно, не SuppressFinalize.

И это означает, что полная (официальная) реализация этого шаблона необходима только из-за возможности наследования Test от.
Обратите внимание, что Dispose(bool) защищен.Когда вы объявляете тестирование в классе sealed, совершенно безопасно и не допускать ~Testing().

2 голосов
/ 06 января 2011

Первая часть:

Когда вызывается GC.SupressFinalize(this), GC информируется, что объект уже освободил свои ресурсы, и его можно собирать как любой другой объект. И да, финализация и «деструкторы» - это одно и то же в .NET.

Вторая часть:

Финализация выполняется отдельным потоком, и мы не контролируем время и порядок финализации, поэтому мы не знаем, доступны ли какие-либо другие объекты или уже завершены. По этой причине вы не можете ссылаться на другие объекты вне блока disposing.

1 голос
/ 19 ноября 2015

В подавляющем большинстве случаев, когда объект, владеющий IDisposable ресурсами, завершен, по крайней мере одно из следующих утверждений будет применяться к каждому из этих ресурсов:

  1. Он уже завершен, в этом случае очистка не требуется.
  2. Его финализатор еще не запущен, но запланирован на это, и в этом случае очистка не требуется.
  3. Его можно очистить тольковнутри определенного потока (который не является потоком финализатора), и в этом случае поток финализатора не должен пытаться очистить его.
  4. Он все еще может использоваться кем-то другим, и в этом случае поток финализаторане пытайтесь очистить его.

В некоторых редких случаях, когда ничего из вышеперечисленного не применимо, очистка в финализаторе может быть уместной, но не следует даже рассматривать это, если у вас нет первогорассмотрены четыре вышеупомянутые возможности.

...