Почему некоторые люди используют метод Finalize
по методу Dispose
?
В каких ситуациях вы бы использовали метод Finalize
по методу Dispose
и наоборот?
Почему некоторые люди используют метод Finalize
по методу Dispose
?
В каких ситуациях вы бы использовали метод Finalize
по методу Dispose
и наоборот?
Другие уже рассмотрели разницу между Dispose
и Finalize
(кстати, метод Finalize
по-прежнему называется деструктором в спецификации языка), поэтому я просто немного расскажу о сценариях, в которых метод Finalize
пригодится.
Некоторые типы инкапсулируют одноразовые ресурсы таким образом, чтобы их было легко использовать и уничтожать в одном действии. Общее использование часто выглядит так: открывать, читать или писать, закрывать (Dispose). Он очень хорошо подходит к using
конструкции.
Другие немного сложнее. WaitEventHandles
для экземпляров не используются так, как они используются для передачи сигналов от одного потока к другому. Тогда возникает вопрос, кто должен называть Dispose
? Поскольку такие типы защиты, как они, реализуют метод Finalize
, который гарантирует, что ресурсы будут удалены, когда экземпляр больше не ссылается на приложение.
Метод finalizer вызывается, когда ваш объект собирает мусор, и у вас нет гарантии, когда это произойдет (вы можете заставить его, но это повредит производительности).
Метод Dispose
, с другой стороны, должен вызываться кодом, создавшим ваш класс, чтобы вы могли очищать и освобождать любые приобретенные вами ресурсы (неуправляемые данные, подключения к базе данных, файлы и т.д.). момент кода выполняется с вашим объектом.
Стандартная практика заключается в реализации IDisposable
и Dispose
, чтобы вы могли использовать свой объект в статусе using
. Например, using(var foo = new MyObject()) { }
. И в своем финализаторе вы вызываете Dispose
, на всякий случай, когда код вызова забыл распорядиться вами.
Finalize - это метод обратного хода, вызываемый сборщиком мусора, когда он восстанавливает объект. Dispose - это метод "детерминированной очистки", называемый приложениями для выпуска ценных собственных ресурсов (дескрипторы окон, подключения к базам данных и т.д.), Когда они больше не нужны, вместо того, чтобы оставлять их на неопределенное время, пока GC не обходит объект.
Как пользователь объекта, вы всегда используете Dispose. Finalize для GC.
Как разработчик класса, если у вас есть управляемые ресурсы, которые должны быть удалены, вы реализуете Dispose. Если вы используете собственные ресурсы, вы реализуете как Dispose, так и Finalize, и оба вызываете общий метод, который освобождает собственные ресурсы. Эти идиомы обычно объединяются с помощью частного метода Dispose (bool disposing), который Dispose вызывает с true и Finalize вызовы с false. Этот метод всегда освобождает собственные ресурсы, затем проверяет параметр утилизации, и, если он прав, он управляет управляемыми ресурсами и вызывает GC.SuppressFinalize.
Доработка
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
.Finalize вызывается GC, когда этот объект больше не используется.
Dispose - это обычный метод, который пользователь этого класса может вызывать для освобождения любых ресурсов.
Если пользователь забыл вызвать Dispose и если класс реализовал Finalize, GC будет удостовериться, что он вызван.
Есть некоторые ключи из книги 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);
}
}
}
В 99% случаев вам тоже не придется беспокоиться.:) Но если ваши объекты содержат ссылки на неуправляемые ресурсы (например, дескрипторы окон, дескрипторы файлов), вам необходимо предоставить способ для вашего управляемого объекта освободить эти ресурсы. Finalize дает неявный контроль над выпуском ресурсов. Он вызывается сборщиком мусора. Dispose - это способ дать явный контроль над выпуском ресурсов и может быть вызван напрямую.
Намного больше узнать о теме Garbage Collection, но это начало.
Финализатор предназначен для неявной очистки - вы должны использовать его всякий раз, когда класс управляет ресурсами, которые абсолютно должен быть очищен, так как иначе вы будете утечка дескрипторов/памяти и т.д.
Правильная реализация финализатора, как известно, сложна и ее следует избегать везде, где это возможно - класс SafeHandle
(avaialble in.Net v2.0 и выше) теперь означает, что вам очень редко (если вообще когда-либо) необходимо больше реализовать финализатор.
Интерфейс IDisposable
предназначен для явной очистки и гораздо чаще используется - вы должны использовать это, чтобы позволить пользователям явно освобождать или очищать ресурсы всякий раз, когда они заканчивают использование объекта.
Обратите внимание, что если у вас есть финализатор, вы также должны реализовать интерфейс IDisposable
, чтобы позволить пользователям явно освобождать эти ресурсы раньше, чем они были бы, если бы объект был собран мусором.
См. DG Update: Dispose, Finalization и Resource Management для того, что я считаю лучшим и самым полным набором рекомендаций для финализаторов и IDisposable
.
Резюме -
Кроме того, еще одно отличие состоит в том, что в реализации 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);
}
Прошло много времени, но вы можете прочитать это http://blog.stephencleary.com/2009/08/how-to-implement-idisposable-and.html
Лучший пример, который я знаю.
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
}
}
Diff между методами Finalize и Dispose в С#.
GC вызывает метод finalize для восстановления неуправляемых ресурсов (таких как файловая операция, windows api, сетевое подключение, подключение к базе данных), но время не фиксируется, когда GC называет его. Он называется неявно GC, это означает, что у нас нет контроля низкого уровня.
Dispose Method: У нас есть низкий уровень контроля над ним, как мы его называем, из кода. мы можем вернуть неуправляемые ресурсы всякий раз, когда считаем, что они непригодны для использования. Мы можем достичь этого, реализуя шаблон IDisposal.
Экземпляры классов часто инкапсулируют контроль над ресурсами, которые не управляются средой выполнения, такими как дескрипторы окон (HWND), подключения к базе данных и т.д. Поэтому вы должны предоставить как явный, так и неявный способ освобождения этих ресурсов. Обеспечьте неявный контроль, реализуя защищенный метод Finalize для объекта (синтаксис деструктора в С# и управляемые расширения для С++). Сборщик мусора вызывает этот метод в какой-то момент после того, как больше нет действительных ссылок на объект. В некоторых случаях вы можете предоставить программистам, использующим объект с возможностью явного освобождения этих внешних ресурсов до того, как сборщик мусора освободит объект. Если внешний ресурс является дефицитным или дорогостоящим, более высокая производительность может быть достигнута, если программист явно освобождает ресурсы, когда они больше не используются. Чтобы обеспечить явный контроль, реализуйте метод Dispose, предоставляемый интерфейсом IDisposable. Потребитель объекта должен вызывать этот метод, когда он выполняется с использованием объекта. Dispose можно вызывать, даже если другие ссылки на объект живы.
Обратите внимание, что даже если вы предоставляете явный контроль посредством Dispose, вы должны предоставить неявную очистку, используя метод Finalize. Finalize предоставляет резервную копию для предотвращения утечки ресурсов, если программисту не удается вызвать Dispose.
Как известно, утилизация и финализация используются для освобождения неуправляемых ресурсов. но разница заканчивается, использует два цикла для освобождения ресурсов, где в качестве утилиты используется один цикл.
Чтобы ответить на первую часть, вы должны привести примеры, когда люди используют разные подходы для одного и того же объекта класса. Иначе трудно (или даже странно) ответить.
Что касается второго вопроса, то лучше сначала прочитать это Правильное использование интерфейса IDisposable, который утверждает, что
Это твой выбор! Но выберите Dispose.
Другими словами: сборщик мусора знает только о финализаторе (если таковой имеется. Также известен как деструктор для Microsoft). Хороший код попытается очистить от обоих (финализатор и удаление).