Жизненный цикл объекта. Уничтожение объектов.
Вспомните, что в прежних версиях VB в каждом классе существовало событие Terminate, которое гарантированно вызывалось в тот момент, когда количество ссылок уменьшалось до 0 (в терминологии ООП это называется детерминированным завершением). В VB.NET (как бы вы к этому ни относились) поддерживается только недетерминированное завершение, из чего следует, что вы не можете рассчитывать на то, что некий аналог события Termi nate будет вызван в определенный момент времени. Более того, не гарантировано даже то, что он вообще будет когда-нибудь вызван!
Примечание
Некоторые программисты считают Finalize аналогом события Terminate в VB.NET, однако эта аналогия неверна. Метод Finalize всего лишь содержит код, который должен выполняться при освобождении памяти вашего объекта в процессе сборки мусора. Но поскольку вы не можете явно управлять тем, когда это произойдет, мы настоятельно рекомендуем использовать Finalize лишь как дополнительную меру безопасности – например, для дублирования метода Dispose, который должен вызываться пользователем класса. Метод Dispose рассматривается ниже.
Возникает вопрос: если раньше мы проводили деинициализацию класса в событии Terminate, как же это делается сейчас? Для решения этой проблемы в VB.NET существует очень важное правило:
Если ваш класс должен освобождать какие-либо внешние ресурсы, кроме обычной памяти (например, подключения к базе данных, графические контексты, файловые манипуляторы и т.. д.), он должен содержать метод с именем Di spose, вызываемый из внешнего кода.
Мы вернемся к методу Dispose при рассмотрении интерфейса IDisposable в главе 5. А пока достаточно сказать, что любое графическое приложение – даже самое простое, вроде продемонстрированного в главе 1, – относится к категории программ, в которых необходим метод Dispose. Это связано с тем, что графические программы захватывают так называемые графические контексты, которые должны быть освобождены для возвращения ресурсов в систему (графические контексты не являются блоками памяти, поэтому автоматическая сборка мусора в данном случае не поможет).
Теперь становится ясно, почему в автоматически сгенерированный код, приведенный в главе 1, входит вызов Dispose. Недетерминированное завершение относится к числу самых неоднозначных нововведений .NET, однако автоматическая сборка мусора является неотъемлемой частью .NET. Разработчикам при всем желании не удалось бы сохранить прежний, детерминированный вариант управления памятью и обеспечить совместимость с .NET. Кроме того, механизму, использованному в старых версиях VB (подсчет ссылок), присущи проблемы с утечкой памяти, вызванной существованием циклических ссылок, когда объект А ссылается на объект В и наоборот, как показано на рис. 4.8.
Примечание
Такие языки, как Java, наглядно доказали, что преимущества от автоматической сборки мусора оправдывают небольшие изменения в стиле программирования, связанные с отсутствием детерминированного завершения.
Рис. 4.8. Две разновидности циклических ссылок