Завершить против Dispose

Почему некоторые люди используют метод Finalize по методу Dispose?

В каких ситуациях вы бы использовали метод Finalize по методу Dispose и наоборот?

Ответ 1

Другие уже рассмотрели разницу между Dispose и Finalize (кстати, метод Finalize по-прежнему называется деструктором в спецификации языка), поэтому я просто немного расскажу о сценариях, в которых метод Finalize пригодится.

Некоторые типы инкапсулируют одноразовые ресурсы таким образом, чтобы их было легко использовать и уничтожать в одном действии. Общее использование часто выглядит так: открывать, читать или писать, закрывать (Dispose). Он очень хорошо подходит к using конструкции.

Другие немного сложнее. WaitEventHandles для экземпляров не используются так, как они используются для передачи сигналов от одного потока к другому. Тогда возникает вопрос, кто должен называть Dispose? Поскольку такие типы защиты, как они, реализуют метод Finalize, который гарантирует, что ресурсы будут удалены, когда экземпляр больше не ссылается на приложение.

Ответ 2

Метод finalizer вызывается, когда ваш объект собирает мусор, и у вас нет гарантии, когда это произойдет (вы можете заставить его, но это повредит производительности).

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

Стандартная практика заключается в реализации IDisposable и Dispose, чтобы вы могли использовать свой объект в статусе using. Например, using(var foo = new MyObject()) { }. И в своем финализаторе вы вызываете Dispose, на всякий случай, когда код вызова забыл распорядиться вами.

Ответ 3

Finalize - это метод обратного хода, вызываемый сборщиком мусора, когда он восстанавливает объект. Dispose - это метод "детерминированной очистки", называемый приложениями для выпуска ценных собственных ресурсов (дескрипторы окон, подключения к базам данных и т.д.), Когда они больше не нужны, вместо того, чтобы оставлять их на неопределенное время, пока GC не обходит объект.

Как пользователь объекта, вы всегда используете Dispose. Finalize для GC.

Как разработчик класса, если у вас есть управляемые ресурсы, которые должны быть удалены, вы реализуете Dispose. Если вы используете собственные ресурсы, вы реализуете как Dispose, так и Finalize, и оба вызываете общий метод, который освобождает собственные ресурсы. Эти идиомы обычно объединяются с помощью частного метода Dispose (bool disposing), который Dispose вызывает с true и Finalize вызовы с false. Этот метод всегда освобождает собственные ресурсы, затем проверяет параметр утилизации, и, если он прав, он управляет управляемыми ресурсами и вызывает GC.SuppressFinalize.

Ответ 4

Доработка

  • Финализаторы должны всегда быть protected, а не public или private, чтобы метод не вызывался из кода приложения напрямую и в то же время, он может сделать вызов метода base.Finalize
  • Финализаторы должны освобождать только неуправляемые ресурсы.
  • Структура не гарантирует, что финализатор будет выполняться вообще на любом данном экземпляре.
  • Никогда не выделяйте память в финализаторах или не вызывайте виртуальные методы из финализаторов.
  • Избегайте синхронизации и повышения необработанных исключений в финализаторах.
  • Порядок выполнения финализаторов не является детерминированным - другими словами, вы не можете полагаться на другой объект, который все еще доступен в вашем финализаторе.
  • Не задавайте финализаторы типов значений.
  • Не создавайте пустые деструкторы. Другими словами, вы никогда не должны явно определять деструктор, если ваш класс не должен очищать неуправляемые ресурсы, и если вы его определяете, он должен выполнить определенную работу. Если позже вам больше не нужно очищать неуправляемые ресурсы в деструкторе, полностью удалите его.

Dispose

  • Внедрить IDisposable для каждого типа с финализатором
  • Убедитесь, что объект сделан непригодным после вызова метода Dispose. Другими словами, избегайте использования объекта после вызова метода Dispose.
  • Вызовите Dispose для всех типов IDisposable, когда вы закончите с ними.
  • Разрешить Dispose вызывать несколько раз, не вызывая ошибок.
  • Запретить последующие вызовы финализатору из метода Dispose с помощью метода GC.SuppressFinalize
  • Избегайте создания одноразовых типов значений
  • Избегайте бросать исключения из методов Dispose

Dispose/Finalized Pattern

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

Ответ 5

Finalize вызывается GC, когда этот объект больше не используется.

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

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

Ответ 6

Есть некоторые ключи из книги MCSD Certification Toolkit (экзамен 70-483) стр. 193:

деструктор ≈ (он почти равен) base.Finalize(). Деструктор преобразуется в переопределенную версию метода Finalize, который выполняет код деструкторов, а затем вызывает метод Finalize базовых классов. Тогда его полностью недетерминированный, который вы не сможете узнать, когда будет вызван, потому что зависит от GC.

Если класс не содержит управляемых ресурсов и неуправляемых ресурсов, ему не нужно реализация IDisposableor имеет деструктор.

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

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

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

Метод Dispose должен освобождать как управляемые, так и неуправляемые ресурсы.

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

После освобождения ресурсов деструктор должен вызвать GC.SuppressFinalize, поэтому объект может пропустите очередь финализации.

Пример реализации для класса с неуправляемыми и управляемыми ресурсами:

using System;

class DisposableClass : IDisposable
{
    // A name to keep track of the object.
    public string Name = "";

    // Free managed and unmanaged resources.
    public void Dispose()
    {

        FreeResources(true);
    }

    // Destructor to clean up unmanaged resources
    // but not managed resources.
    ~DisposableClass()
    {
        FreeResources(false);
    }

    // Keep track if whether resources are already freed.
    private bool ResourcesAreFreed = false;

    // Free resources.
    private void FreeResources(bool freeManagedResources)
    {
        Console.WriteLine(Name + ": FreeResources");
        if (!ResourcesAreFreed)
        {
            // Dispose of managed resources if appropriate.
            if (freeManagedResources)
            {
                // Dispose of managed resources here.
                Console.WriteLine(Name + ": Dispose of managed resources");
            }

            // Dispose of unmanaged resources here.
            Console.WriteLine(Name + ": Dispose of unmanaged resources");

            // Remember that we have disposed of resources.
            ResourcesAreFreed = true;

            // We don't need the destructor because
            // our resources are already freed.
            GC.SuppressFinalize(this);
        }
    }
}

Ответ 7

В 99% случаев вам тоже не придется беспокоиться.:) Но если ваши объекты содержат ссылки на неуправляемые ресурсы (например, дескрипторы окон, дескрипторы файлов), вам необходимо предоставить способ для вашего управляемого объекта освободить эти ресурсы. Finalize дает неявный контроль над выпуском ресурсов. Он вызывается сборщиком мусора. Dispose - это способ дать явный контроль над выпуском ресурсов и может быть вызван напрямую.

Намного больше узнать о теме Garbage Collection, но это начало.

Ответ 8

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

Правильная реализация финализатора, как известно, сложна и ее следует избегать везде, где это возможно - класс SafeHandle (avaialble in.Net v2.0 и выше) теперь означает, что вам очень редко (если вообще когда-либо) необходимо больше реализовать финализатор.

Интерфейс IDisposable предназначен для явной очистки и гораздо чаще используется - вы должны использовать это, чтобы позволить пользователям явно освобождать или очищать ресурсы всякий раз, когда они заканчивают использование объекта.

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

См. DG Update: Dispose, Finalization и Resource Management для того, что я считаю лучшим и самым полным набором рекомендаций для финализаторов и IDisposable.

Ответ 9

Резюме -

  • Вы пишете финализатор для вашего класса, если он имеет ссылку на неуправляемые ресурсы, и вы хотите убедиться, что эти неуправляемые ресурсы освобождаются, когда экземпляр этого класса собирается автоматически. Обратите внимание, что вы не можете вызывать Finalizer объекта в явном виде - он вызывается сборщиком мусора автоматически по мере необходимости.
  • С другой стороны, вы реализуете интерфейс IDisposable (и, следовательно, определяете метод Dispose() как результат для вашего класса), когда у вашего класса есть ссылка на неуправляемые ресурсы, но вы не хотите ждать, пока сборщик мусора вступит в действие (который может быть в любое время - не под контролем программиста) и хочет освободить эти ресурсы, как только вы закончите. Таким образом, вы можете явно освобождать неуправляемые ресурсы, вызывая метод Dispose() объекта.

Кроме того, еще одно отличие состоит в том, что в реализации Dispose() вы также должны освобождать управляемые ресурсы, тогда как в Finalizer это делать не следует. Это связано с тем, что весьма вероятно, что управляемые ресурсы, на которые ссылается объект, уже очищены до того, как он будет готов к финализации.

Для класса, который использует неуправляемые ресурсы, рекомендуется определить оба метода - Dispose() и Finalizer - для использования в качестве запасного варианта на случай, если разработчик забудет явно избавиться от объекта. Оба могут использовать общий метод для очистки управляемых и неуправляемых ресурсов:

class ClassWithDisposeAndFinalize : IDisposable
{
    // Used to determine if Dispose() has already been called, so that the finalizer
    // knows if it needs to clean up unmanaged resources.
     private bool disposed = false;

     public void Dispose()
     {
       // Call our shared helper method.
       // Specifying "true" signifies that the object user triggered the cleanup.
          CleanUp(true);

       // Now suppress finalization to make sure that the Finalize method 
       // doesn't attempt to clean up unmanaged resources.
          GC.SuppressFinalize(this);
     }
     private void CleanUp(bool disposing)
     {
        // Be sure we have not already been disposed!
        if (!this.disposed)
        {
             // If disposing equals true i.e. if disposed explicitly, dispose all 
             // managed resources.
            if (disposing)
            {
             // Dispose managed resources.
            }
             // Clean up unmanaged resources here.
        }
        disposed = true;
      }

      // the below is called the destructor or Finalizer
     ~ClassWithDisposeAndFinalize()
     {
        // Call our shared helper method.
        // Specifying "false" signifies that the GC triggered the cleanup.
        CleanUp(false);
     }

Ответ 11

Лучший пример, который я знаю.

 public abstract class DisposableType: IDisposable
  {
    bool disposed = false;

    ~DisposableType()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(false);
      }
    }

    public void Dispose()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(true);
        GC.SuppressFinalize(this);
      }
    }

    public void Close()
    {
      Dispose();
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposing) 
      {
        // managed objects
      }
      // unmanaged objects and resources
    }
  }

Ответ 12

Diff между методами Finalize и Dispose в С#.

GC вызывает метод finalize для восстановления неуправляемых ресурсов (таких как файловая операция, windows api, сетевое подключение, подключение к базе данных), но время не фиксируется, когда GC называет его. Он называется неявно GC, это означает, что у нас нет контроля низкого уровня.

Dispose Method: У нас есть низкий уровень контроля над ним, как мы его называем, из кода. мы можем вернуть неуправляемые ресурсы всякий раз, когда считаем, что они непригодны для использования. Мы можем достичь этого, реализуя шаблон IDisposal.

Ответ 13

Экземпляры классов часто инкапсулируют контроль над ресурсами, которые не управляются средой выполнения, такими как дескрипторы окон (HWND), подключения к базе данных и т.д. Поэтому вы должны предоставить как явный, так и неявный способ освобождения этих ресурсов. Обеспечьте неявный контроль, реализуя защищенный метод Finalize для объекта (синтаксис деструктора в С# и управляемые расширения для С++). Сборщик мусора вызывает этот метод в какой-то момент после того, как больше нет действительных ссылок на объект. В некоторых случаях вы можете предоставить программистам, использующим объект с возможностью явного освобождения этих внешних ресурсов до того, как сборщик мусора освободит объект. Если внешний ресурс является дефицитным или дорогостоящим, более высокая производительность может быть достигнута, если программист явно освобождает ресурсы, когда они больше не используются. Чтобы обеспечить явный контроль, реализуйте метод Dispose, предоставляемый интерфейсом IDisposable. Потребитель объекта должен вызывать этот метод, когда он выполняется с использованием объекта. Dispose можно вызывать, даже если другие ссылки на объект живы.

Обратите внимание, что даже если вы предоставляете явный контроль посредством Dispose, вы должны предоставить неявную очистку, используя метод Finalize. Finalize предоставляет резервную копию для предотвращения утечки ресурсов, если программисту не удается вызвать Dispose.

Ответ 14

Как известно, утилизация и финализация используются для освобождения неуправляемых ресурсов. но разница заканчивается, использует два цикла для освобождения ресурсов, где в качестве утилиты используется один цикл.

Ответ 15

Чтобы ответить на первую часть, вы должны привести примеры, когда люди используют разные подходы для одного и того же объекта класса. Иначе трудно (или даже странно) ответить.

Что касается второго вопроса, то лучше сначала прочитать это Правильное использование интерфейса IDisposable, который утверждает, что

Это твой выбор! Но выберите Dispose.

Другими словами: сборщик мусора знает только о финализаторе (если таковой имеется. Также известен как деструктор для Microsoft). Хороший код попытается очистить от обоих (финализатор и удаление).