Зачем вызывать dispose(false) в деструкторе?
Ниже приведен типичный пример шаблона удаления:
public bool IsDisposed { get; private set; }
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!IsDisposed)
{
if (disposing)
{
//perform cleanup here
}
IsDisposed = true;
}
}
~MyObject()
{
Dispose(false);
}
Я понимаю, что делает dispose, но я не понимаю, почему вы захотите вызвать dispose (false) в деструкторе? Если вы посмотрите на определение, оно ничего не даст, так зачем кому-то писать такой код? Разве не имеет смысла просто не вызывать избавиться от деструктора вообще?
6 ответов
Финализатор используется в качестве запасного варианта, если объект по какой-то причине не расположен должным образом. Обычно Dispose()
будет вызван метод, который удаляет подключение финализатора и превращает объект в обычный управляемый объект, который сборщик мусора может легко удалить.
Вот пример из MSDN класса, который имеет управляемые и неуправляемые ресурсы для очистки.
Обратите внимание, что управляемые ресурсы очищаются только в том случае, если disposing
Это правда, но неуправляемые ресурсы всегда очищаются.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
"Идея заключается в том, что Dispose(Boolean) знает, вызывается ли он для явной очистки (логическое значение true), а не вызывается из-за сборки мусора (Boolean - false). Это различие полезно, поскольку при утилизации в явном виде метод Dispose(Boolean) может безопасно выполнять код, используя поля ссылочного типа, которые ссылаются на другие объекты, точно зная, что эти другие объекты еще не завершены или не удалены. Когда Boolean равен false, метод Dispose(Boolean) должен не выполнять код, который ссылается на поля ссылочного типа, потому что эти объекты, возможно, уже были завершены."
В " Руководстве по проектированию утилизации, финализации и управления ресурсами" гораздо больше информации.
Изменить: ссылка.
В C# нет деструкторов. Это финализатор, а это совсем другое.
Различие в том, нужно ли вам убирать управляемые объекты или нет. Вы не хотите пытаться очистить их в финализаторе, поскольку они, возможно, сами были завершены.
Я только недавно случайно заглянул на страницу Destructors в Руководстве по программированию в C#. Это показывает, что я ошибся в своем ответе выше. В частности, есть разница между деструктором и финализатором:
class Car
{
~Car() // destructor
{
// cleanup statements...
}
}
эквивалентно
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
Я думаю, что путаница связана с тем, что в вашем примере вы не освобождаете какие-либо неуправляемые ресурсы. Они также должны быть освобождены, когда dispose вызывается через сборщик мусора, и они будут освобождены вне проверки для disposing
, См. Пример MSDN, касающийся освобождения неуправляемых ресурсов. Другое, что могло бы произойти вне проверки, это вызов любого метода Dispose базового класса.
Из цитируемой статьи:
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Release managed resources.
}
// Release unmanaged resources.
// Set large fields to null.
// Call Dispose on your base class.
base.Dispose(disposing);
}
Внутри if(распоряжения) вы должны вызывать dispose/close для управляемых объектов, которые имеют неуправляемые ресурсы (например, соединения с базой данных). Когда вызывается финализатор, эти объекты более недоступны, поэтому сами объекты могут быть завершены, а вы - нет. нужно позвонить распоряжаться им. Также порядок завершения не определен, поэтому вы можете вызывать dispose для уже удаленных объектов.
В следующем примере показано, как создать класс ресурсов, реализующий интерфейс IDisposable: https://msdn.microsoft.com/en-us/library/System.IDisposable.aspx
Функция Dispose(bool dispose): если утилизация равна true, метод вызван прямо или косвенно вашим кодом. Управляемые и неуправляемые ресурсы могут быть утилизированы. Если удаление равно false, метод был вызван средой выполнения из финализатора, и вы не должны ссылаться на другие объекты. Только неуправляемые ресурсы могут быть утилизированы.