Почему лучше не использовать finalize для очистки? .СЕТЬ

(Созданные Windows API объекты, файлы, объекты подключения к базе данных, COM-объекты и т. д.) выходят за рамки .NET Framework. Мы должны явно очистить наши ресурсы. Для этих типов объектов .NET Framework предоставляет метод Object.Finalize, который можно переопределить и очистить код для неуправляемых ресурсов...

  1. Почему лучше не использовать finalize для очистки?

  2. Что уместно использовать?


person RamHS    schedule 03.10.2013    source источник


Ответы (1)


Предпочтительным способом является реализация IDisposable вместе с шаблоном удаления. Финализаторы ограничены по времени, и GC завершит финализатор, если он блокируется слишком долго — это основная причина, по которой его следует избегать, где это возможно.

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

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

IDisposable соответствует ключевому слову using в C#. Все, что реализует этот интерфейс, можно использовать таким образом:

using (var myDisposableItem = new MyDisposableItem())
{
} // Dispose will be called here for you.

Итак, с точки зрения вызова это очень просто.

В .NET Framework есть различные типы, которые реализуют IDisposable, но не имеют ничего для удаления. Я всегда советую действовать так, как будто им нужно избавляться напрямую, потому что в публичном контракте указано, что у них есть что утилизировать, даже если в реализации этого нет. Не программируйте детали реализации.

person Adam Houldsworth    schedule 03.10.2013
comment
Спасибо за очень хороший ответ. Мне было интересно, в чем разница между С++ RAII и IDISPOSABLE? - person RamHS; 03.10.2013
comment
@RamizHassan RAII как концепция не сравнима с IDisposable, но чтобы ответить на вопрос о том, что произойдет в случае возникновения исключения, если вы находитесь внутри оператора using, будет вызван метод Dispose, потому что компилятор генерирует try-finally для него. - person Adam Houldsworth; 03.10.2013
comment
Смысл оператора using C# состоит в том, чтобы иметь хороший блок try finally вокруг кода IDisposable. Соедините эти две вещи, и мы получим RAII?? - person RamHS; 03.10.2013
comment
Ваше последнее предложение (Не программируйте детали реализации) не вычисляется по сравнению со всеми классами в .NET, которые являются IDisposable без необходимости, потому что производный тип может понадобиться позже, и все те классы, которые унаследованы IDisposable объект без родительского объекта IDisposable. Интерфейс IDisposable — это деталь реализации. Вам нужно вызвать using (existingObject as IDisposable) { ... }, чтобы поймать все случаи, когда производная реализация является IDisposable, но в документации (и реализации) родителя IDisposable не упоминается. - person sisve; 03.10.2013
comment
Я бы сказал, что если производный класс полагается на вызов dispose в контексте базового класса, это означает, что публичный контракт был нарушен. - person Adam Houldsworth; 03.10.2013