Dispose() для очистки управляемых ресурсов?
В этом ответе я нашел,
Очистите неуправляемые ресурсы в методе 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.
Ошибочно, я редактировал этот ответ.
2 ответа
Вижу это очень просто.
- Если вы имеете дело с неуправляемыми ресурсами - реализуйте оба
Dispose
а такжеFinalize
,Dispose
должен вызывать разработчиков, чтобы освободить ресурсы, как только они увидят, что они им больше не нужны. Если они забывают позвонитьDispose
затем Framework вызывает финализацию в своем собственном цикле GC (обычно это займет свое время). - Если вы НЕ имеете дело с неуправляемыми ресурсами - тогда ничего не делайте. Не осуществлять
Finalize
ниDispose
, - Если ваш объект использует одноразовые объекты внутри - вы реализуете
Dispose()
если вы создали и сохранили ссылку на любой объект типа, который реализуетDispose()
и который вы еще не утилизировали.
Несколько классических примеров:
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 (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);
}
}
Вот старый вопрос, объясняющий это
Если Foo
имеет ресурсы, которые выиграют от детерминированной очистки, но ни один из которых не может быть эффективно очищен в финализаторе, он должен реализовать IDisposable
но не должен переопределять Finalize
или есть деструктор. Если класс содержит несколько ресурсов, и хотя бы один из них может быть очищен в финализаторе, то каждый отдельный ресурс, который может быть очищен в финализаторе, должен быть инкапсулирован в свой собственный объект, оснащенный финализатором / деструктором (который может быть определен в защищенный вложенный класс), и класс, который будет содержать эти ресурсы, должен содержать ссылки на объекты-оболочки. Как только это будет сделано, внешний класс будет соответствовать шаблону для классов с Dispose
метод, но не финализатор / деструктор.