Поделиться через


Время существования объекта: как создаются и уничтожаются объекты (Visual Basic)

Экземпляр класса (объект) создается с помощью ключевого слова New. Задачи инициализации часто должны выполняться над новыми объектами перед их использованием. Распространенные задачи инициализации включают открытие файлов, подключение к базам данных и чтение значений разделов реестра. Visual Basic управляет инициализацией новых объектов с помощью процедур, называемых конструкторами (специальные методы , которые позволяют контролировать инициализацию).

После выхода объекта из области видимости он освобождается общей языковой средой выполнения (CLR). Visual Basic управляет выпуском системных ресурсов с помощью процедур, называемых деструкторами. Вместе конструкторы и деструкторы поддерживают создание надежных и прогнозируемых библиотек классов.

Использование конструкторов и деструкторов

Конструкторы и деструкторы управляют созданием и уничтожением объектов. Sub New и Sub Finalize процедуры в 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).

Подпрограмма Завершение

Перед освобождением объектов среда CLR автоматически вызывает Finalize метод для объектов, определяющих процедуру Sub Finalize . Метод Finalize может содержать код, который должен выполняться непосредственно перед уничтожением объекта, например код для закрытия файлов и сохранения сведений о состоянии. Существует небольшое снижение производительности при выполнении Sub Finalize, поэтому следует определить метод Sub Finalize только если нужно явно освободить объекты.

Замечание

Сборщик мусора в среде CLR не удаляет неуправляемые объекты, объекты, выполняемые операционной системой непосредственно за пределами среды CLR. Это связано с тем, что различные неуправляемые объекты должны быть удалены различными способами. Эта информация не связана напрямую с неуправляемыми объектами; Его необходимо найти в документации для объекта. Класс, использующий неуправляемые объекты, должен удалять их в методе Finalize .

Деструктор Finalize — это защищенный метод, который можно вызывать только из класса, к которому он принадлежит, или из производных классов. Система автоматически вызывает Finalize при уничтожении объекта, поэтому не следует явно вызывать Finalize, находясь вне реализации производного класса Finalize.

В отличие от Class_Terminate, который выполняется, как только объект устанавливается в null, обычно происходит задержка между тем, как объект выходит за пределы области видимости, и вызовом деструктора 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) в производном классе.

Сборка мусора и деструктор финализации

Платформа .NET Framework использует систему сборки мусора с отслеживанием ссылок для периодического освобождения неиспользуемых ресурсов. Visual Basic 6.0 и более ранних версий использовали другую систему, называемую подсчетом ссылок для управления ресурсами. Хотя обе системы выполняют одну и ту же функцию автоматически, существует несколько важных различий.

CLR периодически уничтожает объекты, когда система определяет, что они больше не нужны. Объекты выпускаются быстрее, когда системные ресурсы находятся в нехватке, а в противном случае — реже. Задержка между моментом, когда объект теряет область видимости, и средой выполнения CLR означает, что, в отличие от объектов в Visual Basic 6.0 и более ранних версиях, невозможно точно определить, когда объект будет уничтожен. В такой ситуации объекты, как говорят, имеют недетерминированное время существования. В большинстве случаев недетерминированное время существования не изменяет способ написания приложений, если вы помните, что Finalize деструктор может не сразу же выполняться при потере области объекта.

Еще одно различие между системами сборки мусора заключается в использовании Nothing. Чтобы воспользоваться преимуществами подсчета ссылок в Visual Basic 6.0 и более ранних версиях, программисты иногда присваивали Nothing переменным объекта, чтобы освободить ссылки, которые удерживали эти переменные. Если переменная содержала последнюю ссылку на объект, ресурсы объекта были немедленно освобождены. В более поздних версиях Visual Basic, в то время как могут возникнуть случаи, в которых эта процедура по-прежнему ценна, выполнение этого процесса никогда не приводит к тому, что указанный объект немедленно освобождает свои ресурсы. Чтобы немедленно освободить ресурсы, используйте метод объекта Dispose , если он доступен. Единственный случай, когда следует присвоить переменной значение Nothing, это когда время жизни переменной значительно превышает то время, которое требуется сборщику мусора для обнаружения заброшенных объектов.

См. также