Initialization and Termination of Components

Your component is initialized by its constructor (Sub New in Visual Basic) and destroyed by its destructor (Sub Finalizein Visual Basic). Your component's constructor is called when an instance of your component is created; the constructor cannot be called thereafter. The destructor is called just before your component is destroyed by garbage collection and its memory is reclaimed.

Visual Basic noteVisual Basic Note

In previous versions of Visual Basic, the Initialize and Terminate events served the same purpose as the constructor and destructor.

Waiting for Garbage Collection

The common language runtime calls your component's destructor after the garbage collection determines that the component can no longer be reached by any executing code. This happens if all references to the component have been released, or if the only references to your component are held by objects that are similarly isolated from all executing code — for example, in the case of circular references.

Because there can be a delay between the moment when a user is finished with your component and the moment when its destructor is called, an additional step is introduced into the lifetime of .NET Framework components: If your component acquires system resources, such as database connections or handles to Windows system objects, you should implement the IDisposable interface, and provide a Dispose method so that users of your component can choose when to release those resources.

Life Cycle of a Component

Type initialization: When the first instance of your component is created, the first code that executes is any shared initialization code. A reference to any shared member will also cause the shared constructor to execute. This includes any shared fields (member variables) that are initialized, and the shared constructor (Shared Sub New) if it exists. In the following code, a reference font is created for the entire class.

Note

The C# keyword that corresponds to Shared is static, which is not to be confused with the Static keyword in 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.
   }
}

Note

Class initialization can occur even if no instances of your component are created. For example, an abstract (MustInherit) class with shared member functions will be initialized and those functions will be available for use by the application, even though no instance of the class is created.

  1. Instance initialization: When an instance of your component is created, data members that have initialization code are initialized, and the appropriate constructor overload is executed. The following code initializes a private field and defines two constructors, one to be called if there are no parameters, and the other to be called if the user specifies parameters.

    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. Disposing of resources: If your component implements the IDisposable interface, it must provide a Dispose method, which the client should call when it is finished using the component. Note that any component that inherits from Component already has a default implementation of Dispose, which can be overridden to provide additional cleanup code. In the Dispose method, your component frees all system resources it may have allocated, releases references to other objects, and renders itself unusable. There may also be instances where it is appropriate for your component to call its own Dispose method. The following code disposes of a dependent object that has a Dispose method.

    ' 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.
    }
    
    

    After you call Dispose, your client should release any remaining references to the component, so that garbage collection can reclaim the component's memory.

  3. Instance destruction: When garbage collection detects that there are no remaining references to the component, the runtime calls your component's destructor (Finalizein Visual Basic) and frees the memory. You should override your base class's Finalize method (for Visual Basic) or implement a destructor (for Visual C#) to implement your own clean-up code, but always include a call to the destructor or Finalize method of the base class.

    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
    }
    

When Should You Implement a Dispose Method?

If your component inherits from Component, a default implementation of Dispose is provided. This implementation can be overridden to provide custom cleanup code. If you are building your component by creating a custom implementation of IComponent, you should implement IDisposable to provide a Dispose method for your component.

Your component needs a Dispose method if it allocates system objects, database connections, or other scarce resources that should be released as soon as a user is finished with the component.

You should also implement a Dispose method if your component holds references to other objects that have Dispose methods.

Why Implement Dispose?

Depending on system activity, an unpredictable interval could elapse between the time a user finishes using your component and the time garbage collection detects that the component's code is unreachable. If you do not provide a Dispose method, your component will continue to hold its resources during this interval.

A Worst-Case Scenario

Imagine a server component that uses a database connection and does not have a Dispose method. On a server with a large amount of memory, you might create and release many instances of the component without having much impact on free memory. In this case, garbage collection might not destroy the components for some time after the references to them are released.

Eventually, all of the available database connections could be tied up by components that had been released but not destroyed. Even though the server had no shortage of memory, it might be unable to respond to user requests.

See Also

Tasks

How to: Create and Configure Components in Design Mode

Reference

Dispose

Finalize

Concepts

Component Class Characteristics

Component Instancing Changes in Visual Basic