Завершить против распоряжаться


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

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

13 180

13 ответов:

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

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

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

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

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

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

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

как пользователь объекта, вы всегда используете Dispose. Финализация - это для ГК.

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

завершить

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

распоряжения

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

Распоряжаться/Завершена Шаблон

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

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

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

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

есть несколько ключей из книги MCSD Certification Toolkit (exam 70-483) pag 193:

деструктор ≈(он почти равен) база.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);
        }
    }
}

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

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

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

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

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

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

посмотреть обновление DG: утилизация, завершение и ресурс Управление за то, что я считаю лучшим и наиболее полным набором рекомендаций по финализаторам и IDisposable.

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

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

разница между методами Finalize и Dispose в C#.

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

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

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

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

резюме -

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

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

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

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

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