Почему традиционный шаблон Dispose подавляет завершение?

Предполагая, что это традиционный шаблон Dispose (взятый из devx, но встречается на многих веб-сайтах)

class Test : IDisposable
{
  private bool isDisposed = false;

  ~Test()
  {
    Dispose(false);
  }

  protected void Dispose(bool disposing)
  {
    if (disposing)
    {
      // Code to dispose the managed resources of the class
    }

    // Code to dispose the un-managed resources of the class

    isDisposed = true;
  }

  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
}

Я не понимаю, почему мы звоним GC.SupressFinalize(this). Это требует, чтобы я написал свое собственное управление управляемыми ресурсами, включая обнуление моих ссылок? Должен признать, я немного растерялся. Может ли кто-нибудь пролить свет на эту закономерность?

В идеале я хотел бы только избавиться от моих неуправляемых ресурсов и позволить сборщику мусора выполнять управляемый сбор самостоятельно.

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


person Lazlo    schedule 19.12.2010    source источник
comment
Разве санкционированный шаблон MS не использует isDisposed при проверке блока очистки управляемого ресурса? if (удаление &&! isDisposed) {}   -  person spender    schedule 20.12.2010
comment
возможный дубликат Когда мне следует использовать GC.SuppressFinalize ()?   -  person Noon Silk    schedule 20.12.2010
comment
Да, возможно. Но это не совсем относится к вопросу.   -  person Lazlo    schedule 20.12.2010
comment
Вам также может быть полезно прочитать это: msdn.microsoft.com / ru-ru / library /   -  person Noon Silk    schedule 20.12.2010


Ответы (5)


Шаблон IDisposable используется для того, чтобы объект мог детерминированно очищать свои ресурсы в момент, когда метод Dispose вызывается клиентским кодом.

Финализатор используется только в качестве запасного варианта на тот случай, если клиентский код по какой-то причине не сможет вызвать Dispose.

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

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

person LukeH    schedule 19.12.2010
comment
Это моя первая реакция, и в этом случае я бы удалил финализатор. Могу ли я заставить других участников или S / O проголосовать за этот ответ, чтобы сказать мне, действительно ли это правильный ответ? - person Lazlo; 20.12.2010
comment
использует только управляемые ресурсы: но если я использовал неуправляемые ресурсы и использую Dispose (), будет ли сборщик мусора автоматически позаботиться об управляемых ресурсах? - person Lazlo; 20.12.2010
comment
@Lazlo: Что ты имеешь в виду? Вы не сможете вызывать Dispose для неуправляемых ресурсов, потому что они не будут реализовывать IDisposable. - person LukeH; 20.12.2010

SuppressFinalize only подавляет любой настраиваемый финализатор.

Это не влияет на другое поведение сборщика мусора.
Вам никогда не нужно явно обнулять ссылки. (Если вы не хотите, чтобы их собирали пораньше)

Нет никакой разницы между классом без финализатора и экземпляром, для которого вы вызвали SuppressFinalize.

Вызов SuppressFinalize предотвращает дополнительный вызов Dispose(false) и несколько ускоряет сборщик мусора. (финализаторы дорогие)

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

person SLaks    schedule 19.12.2010
comment
Разве тот класс, который на самом деле реализует финализатор, не должен вызывать SuppressFinalize? Нет необходимости в классе, который непосредственно не обрабатывает неуправляемые ресурсы, чтобы беспокоиться о гипотетических потомках, которые могут это сделать, или есть? - person LukeH; 20.12.2010
comment
@ Люк: Dispose() не virtual. - person SLaks; 20.12.2010
comment
Нет, но если вы реализуете так называемый IDisposable шаблон (а не просто интерфейсный контракт), тогда вы должны предоставить своим потомкам виртуальный метод Dispose(bool), который можно будет переопределить в случае необходимости. - person LukeH; 20.12.2010
comment
@LukeH: Идея состоит в том, что финализатор должен подавляться только в том случае, если метод Dispose наиболее производного класса завершается успешно, не вызывая исключения. При условии, что виртуальный метод вызывается только из невиртуальной оболочки, шаблон гарантирует это; размещение вызова SuppressFinalize в виртуальном методе - нет. - person supercat; 03.04.2012

From Msdn: «Этот метод устанавливает бит в заголовке объекта, который система проверяет при вызове финализаторов. Параметр obj должен быть вызывающим для этого метода. Объекты, реализующие интерфейс IDisposable, могут вызывать этот метод из IDisposable.Dispose, предотвращающий вызов сборщика мусора Object.Finalize для объекта, которому он не требуется. "

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

person saju    schedule 03.04.2012

Как указано в MSDN при выполнении Finalize метод дорогостоящий. Вызывая dispose, вы уже завершили свой класс самостоятельно, поэтому не нужно вызывать финализатор. Финализатор реализуется в том случае, если Dispose никогда не вызывается напрямую вашим кодом (или тем, кто «владеет» экземпляром).

person Ken Henderson    schedule 19.12.2010

// If the monitor.Dispose method is not called, the example displays the following output:
//       ConsoleMonitor instance....
//       The ConsoleMonitor class constructor.
//       The Write method.
//       The ConsoleMonitor finalizer.
//       The Dispose(False) method.
//       Disposing of unmanaged resources.
//       
// If the monitor.Dispose method is called, the example displays the following output:
//       ConsoleMonitor instance....
//       The ConsoleMonitor class constructor.
//       The Write method.
//       The Dispose method.
//       The Dispose(True) method.
//       Disposing of managed resources.
//       Disposing of unmanaged resources.

Из https://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize(v=vs.110).aspx

person Ali Kerimli    schedule 28.02.2018