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


Инициализация и прекращение работы компонентов

Компоненты инициализируются при помощи конструкторов (Sub New в Visual Basic) и уничтожаются при помощи деструкторов (Sub Finalizeв Visual Basic). Конструктор вызывается при создании экземпляра компонента, после этого он не может быть вызван. Деструктор вызывается непосредственно перед уничтожением объекта в процессе сборки мусора для того, чтобы повторно использовать занимаемую им память.

Примечание Visual BasicПримечание Visual Basic

В более ранних версиях Visual Basic вместо вызова конструктора и деструктора использовались события Initialize и Terminate.

Ожидание сборки мусора

Общеязыковая среда выполнения вызывает деструктор компонента после того, как при сборке мусора будет установлено, что доступ к компоненту из выполняемого кода более невозможен. Это происходит в том случае, когда все ссылки на компонент удалены или все оставшиеся ссылки на компонент исходят из объектов, которые также изолированы от прочего выполняемого кода, например в случае циклических ссылок.

Поскольку между моментом, когда пользователь завершил работу с компонентом, и моментом вызова деструктора существует пауза, в жизненном цикле компонентов .NET появляется дополнительный этап. Если компоненты использовали ресурсы системы, такие как подключения к базам данных или дескрипторы системных объектов Windows, следует включить в компонент интерфейс IDisposable и реализовать метод Dispose, чтобы пользователь компонента мог выбрать, когда освободить используемые ресурсы.

Жизненный цикл компонента

Инициализация типа. При создании первого экземпляра компонента выполняется совместно используемый код инициализации. Ссылка на любой совместно используемый член класса также приводит к выполнению совместно используемого конструктора. В число этих членов класса входят любые совместно используемые поля (переменные-члены класса) и совместно используемый конструктор (Shared Sub New), если он существует. В приведенном ниже коде создается ссылка на шрифт для всего класса.

Примечание

Ключевое слово, соответствующее Shared, в C# — static; не следует путать его с ключевым словом Static в Visual Basic.

Public Class ADrawing
Shared ReadOnly ReferenceFont As New Font("TimesNewRoman", 14)
' Shared constructor does not overload other constructors.
Shared Sub New()
   ' There is no call to the base class's shared constructor.
   ' Insert code to initialize the shared data.
End Sub
End Class
class ADrawing
{
   static Font m_referenceFont = new Font("TimesNewRoman", 14);
   // Simply add the static keyword to create a static constructor.
   // Static constructors do not have any parameters.
   static ADrawing()
   {
      // There is no call to the base class's static constructor.
      // Code to initialize the font here.
   }
}

Примечание

Инициализация класса выполняется, даже если не созданы экземпляры компонента.Например, класс abstract (MustInherit) с общими функциями-членами инициализируется, и эти функции будут доступны для использования приложением, даже если не создан экземпляр класса.

  1. Инициализация экземпляра. При создании экземпляра компонента инициализируются элементы данных с кодом инициализации, и выполняется перегрузка соответствующего конструктора. Следующий код инициализирует закрытое поле и определяет два конструктора, один из которых вызывается при отсутствии параметров, а второй — при задании параметров пользователем.

    Class AShape
       Private answer As Integer = 42
       Public Sub New()
          ' Call another constructor with default initialization values.
          MyClass.New(System.Drawing.Color.Red, 5280, DefinedSizes.Large)
       End Sub
       Public Overloads Sub New(myColor As Color, myLength As Integer, _
                Size As DefinedSizes)
          ' Insert code to initialize the class.
       End Sub
       ' Defines the DefinedSizes enum
       Public Enum DefinedSizes
          Large
          Small
       End Enum
    End Class
    
    class AShape
    {
       private int m_answer = 42;
       // Forward to another constructor.
       public AShape() 
       : this(System.Drawing.Color.Red, 5280, DefinedSizes.Large)
       {
          // Additional initialization goes here.
       }
    
       public AShape(Color color, int length, DefinedSizes size)
       {
          // Code to initialize the class goes here.
       }
       // Defines the DefinedSizes enum
       public enum DefinedSizes
       {
          Large,
          Small
       }
    }
    
  2. Удаление ресурсов. Если компонент реализует интерфейс IDisposable, он должен предоставить метод Dispose, который клиент должен вызвать по завершении использования компонента. Обратите внимание, что любой компонент, наследуемый от Component, уже имеет реализацию Dispose по умолчанию, которую можно переопределить для предоставления дополнительного кода очистки. В методе Dispose компонент высвобождает все системные ресурсы, которые он мог выделить, освобождает ссылки на другие объекты и отображает сам себя в непригодном для использования состоянии. Также могут существовать экземпляры, в которых компонент может вызвать собственный метод Dispose. В следующем коде удаляется зависимый объект с методом Dispose.

    ' Assumes that the class implements IDisposable
    Public Sub Dispose() Implements IDisposable.Dispose
       myWidget.Dispose
       myWidget = Nothing
       ' Insert additional code.
    End Sub
    
    // Assumes that the class implements IDisposable
    public void IDisposable.Dispose()
    {
       mywidget.Dispose();
       mywidget = null;
       // Dispose of remaining objects.
    }
    
    

    После вызова Dispose клиент должен освободить все оставшиеся ссылки на компонент, чтобы сборка мусора могла освободить память компонента.

  3. Удаление экземпляра. Когда сборка мусора обнаруживает, что не осталось ссылок на компонент, среда выполнения вызывает деструктор компонента (Finalizeв Visual Basic) и освобождает память. Следует переопределить метод Finalize базового класса (для Visual Basic) или реализовать деструктор (для Visual C#) для реализации собственного кода очистки, но всегда включать вызов деструктора или метода Finalize базового класса.

    Protected Overrides Sub Finalize()
       m_Gadget = Nothing
       m_Gear = Nothing
       MyBase.Finalize()
    End Sub
    
    // In C#, a destructor is used instead of a Finalize method.
    ~ThisClass()
    {
       m_gadget = null;
       m_gear = null;
       // The base class finalizer is called automatically
    }
    

Когда следует реализовывать метод "Dispose"

Компонент, наследующий от класса Component, содержит стандартную реализацию Dispose. Эту реализацию можно переопределить, чтобы вставить пользовательский код очистки памяти. Если компонент построен на базе пользовательской реализации интерфейса IComponent, необходимо реализовать интерфейс IDisposable, чтобы предоставить компоненту собственный метод Dispose.

Компоненту требуется метод Dispose, если он выделяет память для системных объектов, подключений к базам данных или других дефицитных ресурсов, которые необходимо освободить после завершения работы с компонентом.

Если компонент хранит ссылки на другие объекты, в которых имеется метод Dispose, ему также требуется реализовать метод Dispose.

Зачем реализовывать метод "Dispose"

В зависимости от активности работы системы между моментом, когда пользователь прекращает работу с компонентом, и моментом, когда при сборке мусора обнаруживается неиспользуемый код компонента, может пройти некоторое время. Если не реализовать метод Dispose, компонент будет продолжать удерживать ресурсы в течение всего этого интервала.

Наихудший сценарий

Предположим, что существует серверный компонент, который использует подключение к базе данных и не имеет метода Dispose. На сервере с большим объемом памяти можно создавать и освобождать большое количество экземпляров компонента, не создавая больших проблем со свободной памятью. В этом случае при сборке мусора компоненты будут уничтожены лишь через некоторое время после удаления всех ссылок на них.

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

См. также

Задачи

Практическое руководство. Создание и настройка компонентов в режиме конструктора

Ссылки

Dispose

Finalize

Основные понятия

Характеристики классов компонентов

Изменения в создании экземпляров компонентов в Visual Basic