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