Утилизировать() для очистки управляемых ресурсов?

В этом ответе я нашел,

Очистите неуправляемые ресурсы в методе Finalize и управляемые в методе Dispose, если в вашем коде используется шаблон Dispose/Finalize.

А потом я нашел эту хорошую статью о доработке и утилизации и получил четкое представление о них. В статье есть следующий код (страница 3), чтобы объяснить концепции:

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);
    }
}

Но ниже того же примечания (которое я включил в начало этого вопроса) появляется.

Шаблон Dispose/Finalize Microsoft рекомендует использовать как Dispose, так и Finalize при работе с неуправляемыми ресурсами. Тогда правильная последовательность будет для разработчика, чтобы вызвать Dispose. Реализация Finalize будет запущена, и ресурсы будут по-прежнему освобождаться, когда объект будет подвергаться сборке мусора, даже если разработчик не будет явно вызывать метод Dispose. Франческо Балена пишет в своем блоге: "Шаблон Dispose/Finalize следует использовать только тогда, когда ваш тип вызывает неуправляемый код, который выделяет неуправляемые ресурсы (включая неуправляемую память), и возвращает дескриптор, который вы должны использовать в конечном итоге для освобождения ресурса. связать их с родительскими объектами, вызывая их родительские методы после того, как они утилизировали или завершили свои собственные члены ". Проще говоря, очистите неуправляемые ресурсы в методе Finalize и управляемые в методе Dispose, когда в вашем коде используется шаблон Dispose/Finalize.

Теперь я снова в замешательстве. Во всей статье и в примере кода показано, что неуправляемые ресурсы должны быть освобождены в Dispose(). Но тогда какова актуальность этого комментария?

Редактировать:

Как подтверждается, что эта строка:

Проще говоря, очистите неуправляемые ресурсы в методе Finalize и управляемые в методе Dispose, когда в вашем коде используется шаблон Dispose/Finalize.

Ошибочно, я редактировал этот ответ.

Ответ 1

Вижу это очень просто.

  1. Если вы имеете дело с неуправляемыми ресурсами - используйте Dispose и Finalize. Dispose должен быть призван разработчиками освободить ресурсы, как только они увидят, что они им больше не нужны. Если они забывают вызвать Dispose, то Framework вызывает finalize в своем собственном цикле GC (обычно это займет свое приятное время).
  2. Если ваш объект использует одноразовые объекты для внутреннего использования - вы реализуете Dispose(), если создали и сохранили ссылку на любой объект типа, который реализует Dispose() и который вы еще не утилизировали.
  3. Если ни один из вышеперечисленных случаев не подходит (вы НЕ имеете дело с неуправляемыми ресурсами, а ваш объект не использует одноразовые объекты внутри) - тогда ничего не делайте. Не используйте ни TG46, ни TG47.

Несколько классических примеров:

System.IO.FileStream объект управляет дескрипторами блокировки/потока к файлам. Таким образом, он реализует как распоряжаться, так и завершать. Если разработчик располагает им, другая программа может получить к нему доступ сразу же. Если он забудет утилизировать его, то Framework завершит его и закроет дескрипторы позже в цикле GC.

System.Text.StringBuilder доза не имеет никаких неуправляемых ресурсов. Так что не распоряжайтесь, не дорабатывайте.

Что касается шаблона, что это значит для

// Code to dispose the managed resources of the class

- это вызов методов Dispose любых объектов .NET, которые есть у вас в качестве компонентов внутри этого класса

И

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

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

class Test : IDisposable
{
  private bool isDisposed = false;

  ~Test()
  {
    Dispose(false);
  }

  protected void Dispose(bool disposing)
  {
    if (!isDisposed)
    {
      if (disposing)
      {
        // Code to dispose the managed resources of the class
        internalComponent1.Dispose();
        internalComponent2.Dispose();
      }

      // Code to dispose the un-managed resources of the class
      CloseHandle(handle);
      handle = IntPtr.Zero;   

      isDisposed = true;
    }
  }

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

Вот старый вопрос, объясняющий это

Ответ 2

Если a Foo имеет ресурсы, которые выиграют от детерминированной очистки, но ни один из них не может быть полезен в финализаторе, он должен реализовать IDisposable, но не должен переопределять Finalize или иметь деструктор. Если класс содержит несколько ресурсов, и по крайней мере один может быть очищен в финализаторе, то каждый дискретный ресурс, который может быть очищен в финализаторе, должен быть инкапсулирован в свой собственный объект, снабженный Finalizer/destructor (который может быть определен в защищенный вложенный класс), а класс, содержащий эти ресурсы, должен содержать ссылки на объекты-обертки. Как только это будет сделано, внешний класс будет соответствовать шаблону для классов с помощью метода Dispose, но не финализатор/деструктор.