Время существования: создание и уничтожение объектов (Visual Basic)
Экземпляр класса, объект, создается с помощью ключевого слова New
. Задачи инициализации зачастую необходимо выполнять на новых объектах до их использования. К распространенным задачам инициализации относится открытие файлов, подключение к базам данных и чтение значений параметров реестра. Visual Basic управляет инициализацией новых объектов с помощью процедур, называемых конструкторами (специальные методы , которые позволяют контролировать инициализацию).
Когда объект выходит из области, он высвобождается средой CLR. Visual Basic управляет выпуском системных ресурсов с помощью процедур, называемых деструкторами. Вместе конструкторы и деструкторы поддерживают создание надежных и предсказуемых библиотек класса.
Использование конструкторов и деструкторов
Конструкторы и деструкторы управляют созданием и уничтожением объектов. Sub Finalize
Процедуры Sub New
в Visual Basic инициализировать и уничтожить объекты; они заменяют Class_Initialize
Class_Terminate
методы, используемые в Visual Basic 6.0 и более ранних версиях.
Конструктор Sub New
Конструктор Sub New
может быть запущен только один раз при создании класса. Его нельзя вызвать явным образом нигде, кроме первой строки кода другого конструктора этого же класса или производного класса. Более того, код метода Sub New
всегда выполняется до любого другого кода в классе. Visual Basic неявно создает Sub New
конструктор во время выполнения, если явно не определяется Sub New
процедура для класса.
Чтобы создать конструктор класса, создайте процедуру с именем Sub New
в любом месте определения класса. Чтобы создать конструктор с параметрами, укажите имена и типы данных аргументов в Sub New
точно так же, как для любой процедуры. См. следующий код:
Sub New(ByVal s As String)
Конструкторы часто перегружены, как в следующем коде:
Sub New(ByVal s As String, i As Integer)
При вызове класса, производного от другого класса, первая строка конструктора должна представлять собой вызов конструктора базового класса (кроме случаев, когда в базовом классе есть доступный конструктор, не принимающий параметры). Вызов базового класса, содержащего указанный выше конструктор, может быть, к примеру, таким MyBase.New(s)
. MyBase.New
В противном случае является необязательным, а среда выполнения Visual Basic вызывает ее неявно.
После написания кода для вызова конструктора родительского объекта можно добавить дополнительный код инициализации к процедуре Sub New
. Sub New
может принимать аргументы при вызове в качестве конструктора с параметрами. Эти параметры передаются из процедуры, вызывающей конструктор, например, Dim AnObject As New ThisClass(X)
.
Sub Finalize
Перед высвобождением объектов среда CLR автоматически вызывает метод Finalize
для объектов, определяющих процедуру Sub Finalize
. Метод Finalize
может содержать код, который необходимо выполнить непосредственно перед уничтожением объекта, например, код для закрытия файлов и сохранения информации о состоянии. Существует небольшой спад производительности при выполнении Sub Finalize
, поэтому метод Sub Finalize
нужно определять только в тех случаях, когда требуется явное высвобождение объектов.
Примечание.
Сборщик мусора в среде CLR не удаляет неуправляемые объекты, объекты, выполняемые операционной системой непосредственно за пределами среды CLR. Причина состоит в том, что разные неуправляемые объекты следует уничтожать по-разному. Эта информация не связана напрямую с неуправляемым объектом, ее необходимо найти в документации по объектам. Класс, использующий неуправляемые объекты, должен удалить их в своем методе Finalize
.
Деструктор Finalize
является защищенным методом, который можно вызвать только из класса, к которому он принадлежит, или из производного класса. Система автоматически вызывает Finalize
при уничтожении объекта, поэтому не следует явным образом вызывать Finalize
извне реализации Finalize
производного класса.
В отличие от Class_Terminate
, выполняющегося сразу же при уничтожении объекта, обычно существует пауза между потерей объектом области и вызовом деструктора Finalize
в Visual Basic. Visual Basic .NET позволяет использовать второй тип деструктора, IDisposable.Disposeкоторый можно явно вызывать в любое время для немедленного выпуска ресурсов.
Примечание.
Деструктор Finalize
не должен создавать исключений, поскольку они не обрабатываются приложением и могут привести к завершению работы приложения.
Как методы New и Finalize работают в иерархии классов
При каждом создании экземпляра класса среда CLR пытается выполнить процедуру New
, если она существует в этом объекте. New
— тип процедуры, которая называется constructor
и используется для инициализации новых объектов до выполнения всего остального кода в объекте. Конструктор New
можно использовать для открытия файлов, подключения к базам данных, инициализации переменных и для других задач, которые необходимо выполнить перед использованием объекта.
Когда создается экземпляр производного класса, конструктор Sub New
базового класса выполняется в первую очередь, а затем — конструкторы в производных классах. Это происходит, поскольку первая строка кода в конструкторе Sub New
использует синтаксис MyBase.New()
для вызова конструктора класса на один уровень выше себя в иерархии классов. Затем конструктор Sub New
вызывается для каждого класса в иерархии вплоть до достижения базового класса. На этом этапе выполняется код в конструкторе базового класса, а затем выполняется код в каждом конструкторе всех производных классов; код в производном классе самого дальнего уровня выполняется последним.
Когда объект больше не нужен, среда CLR вызывает метод Finalize для этого объекта перед высвобождением памяти. Метод Finalize называется destructor
, поскольку он выполняет задачи очистки, такие как сохранение информации о состоянии, закрытие файлов и подключений к базам данных, а также прочие задачи, которые необходимо выполнить перед высвобождением объекта.
Интерфейс IDisposable
Экземпляры классов зачастую управляют ресурсами, которыми не управляет среда CLR, такими как дескрипторы Windows и подключения к базам данных. От этих ресурсов нужно избавляться в методе Finalize
класса, поэтому они будут высвобождаться при уничтожении объекта сборщиком мусора. Тем не менее, сборщик мусора уничтожает объекты только в тех случаях, когда среде CLR нужно больше свободной памяти. Это означает, что ресурсы могут быть не высвобождены еще в течение долгого времени после того, как объект выйдет из области.
Чтобы дополнить сборку мусора, ваши классы могут предоставлять механизм активного управления системными ресурсами путем реализации интерфейса IDisposable. В IDisposable существует метод Dispose, который клиенты должны вызывать по завершении использования какого-либо объекта. Можно использовать метод Dispose для немедленного высвобождения ресурсов и выполнения таких задач как закрытие файлов и подключений к базам данных. В отличие от деструктора Finalize
, метод Dispose не вызывается автоматически. Клиенты класса должны явным образом вызвать Dispose, когда нужно немедленно высвободить ресурсы.
Использование IDisposable
Класс, реализующий интерфейс IDisposable, должен включать следующие разделы кода:
Поле, чтобы отслеживать, уничтожен ли объект:
Protected disposed As Boolean = False
Перегрузка Dispose для высвобождения ресурсов класса. Этот метод должен вызываться методами Dispose и
Finalize
базового класса:Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposed Then If disposing Then ' Insert code to free managed resources. End If ' Insert code to free unmanaged resources. End If Me.disposed = True End Sub
Реализация Dispose, содержащая только следующий код:
Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub
Переопределение метода
Finalize
, содержащее только следующий код:Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub
Производное создание от класса, реализующего IDisposable
Классу, производному от базового класса, реализующего интерфейс IDisposable, нет необходимости переопределять какие-либо базовые методы, если только производный класс не использует дополнительные ресурсы, которые следует высвобождать. В этом случае производный класс должен переопределять метод Dispose(disposing)
базового класса, чтобы удалить ресурсы производного класса. Это переопределение должно вызвать метод Dispose(disposing)
базового класса.
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposed Then
If disposing Then
' Insert code to free managed resources.
End If
' Insert code to free unmanaged resources.
End If
MyBase.Dispose(disposing)
End Sub
Производный класс не должен переопределять методы Dispose и Finalize
базового класса. Когда эти методы вызываются из экземпляра производного класса, реализация этих методов в базовом классе вызывает переопределение метода Dispose(disposing)
производного класса.
Сбор мусора и деструктор Finalize
Платформа .NET Framework использует систему сборки мусора для трассировки ссылок для периодического выпуска неиспользуемых ресурсов. Visual Basic 6.0 и более ранних версий использовали другую систему, называемую подсчетом ссылок для управления ресурсами. Обе системы автоматически выполняют одну и ту же функцию, но есть несколько важных различий.
CLR периодически уничтожает объекты, если система определяет, что эти объекты больше не нужны. Объекты высвобождаются быстрее при нехватке системных ресурсов и медленнее в других случаях. Задержка между потерей объектом области и высвобождением объекта средой CLR означает, что в отличие от объектов в Visual Basic 6.0 и более ранних версиях, невозможно точно определить, когда объект будет уничтожен. В такой ситуации объекты, как говорят, имеют недетерминированное время существования. В большинстве случаев неопределенное время жизни не влияет на написание приложений, если помнить о том, что деструктор Finalize
может быть выполнен не сразу после потери объектом области.
Еще одно отличие от систем сборки мусора заключается в использовании Nothing
. Чтобы воспользоваться подсчетом ссылок в Visual Basic 6.0 и более ранних версиях, программисты часто назначали Nothing
переменным объектов, чтобы высвобождать ссылки, удерживаемые этими переменными. Если переменная содержала последнюю ссылку на объект, ресурсы объекта были немедленно высвобождены. В более поздних версиях Visual Basic, хотя по-прежнему могут быть случаи, когда эта процедура еще применима, ее выполнение больше не приводит к немедленному высвобождению ресурсов объектом. Чтобы немедленно высвободить ресурсы, используйте метод объекта Dispose, если он доступен. Для переменной следует устанавливать значение Nothing
лишь в тех случаях, когда ее время жизни достаточно велико по отношению ко времени, за которое сборщик мусора обнаруживает потерянные объекты.