Walkthrough: Authoring a Component with Visual Basic
Components provide reusable code in the form of objects. An application that uses a component's code, by creating objects and calling their properties and methods, is referred to as a client. A client may or may not be in the same assembly as a component it uses.
The following procedures build on each other, so the order in which you perform them is important.
The dialog boxes and menu commands you see might differ from those described in Help depending on your active settings or edition. To change your settings, choose Import and Export Settings on the Tools menu. For more information, see Visual Studio Settings.
To create the CDemoLib class library and the CDemo component
From the File menu, select New and then Project to open the New Project dialog. Select the Class Library project template from the list of Visual Basic project types, and enter CDemoLib in the Name box.
Always specify the name of a new project when you create it. Doing so sets the root namespace, assembly name, and project name, and also ensures that the default component will be in the correct namespace.
In Solution Explorer, right-click CDemoLib and select Properties from the shortcut menu. Notice that the Root namespace box contains CDemoLib.
The root namespace is used to qualify the names of components in the assembly. For example, if two assemblies provide components named CDemo, you can specify your CDemo component using CDemoLib.CDemo.
Close the dialog box.
From the Project menu, choose Add Component. In the Add New Item dialog box, select Component Class and type CDemo.vb. in the Name box. A component named CDemo is added to your class library.
In the Solution Explorer, click the Show All Files button. Open the CDemo.vb node to show the CDemo.Designer.vb file. Right-click CDemo.Designer.vb and choose View Code from the shortcut menu. The code editor opens
Notice the Inherits System.ComponentModel.Component immediately below Partial Public Class CDemo. This section designates the class from which your class inherits. By default, a component inherits from the Component class provided by the system. The Component class provides many features for your component, including the ability to use designers.
Locate Public Sub New(). Select the entire method body and cut it from the CDemo.Designer.vb file by pressing CTRL-X.
In the Solution Explorer, right-click CDemo.vb and choose View Code from the shortcut menu. The code editor opens.
Paste the selection into the body of the CDemo class. This lets you work on New without interference from the designer.
In Solution Explorer, right-click Class1.vb and choose Delete. This deletes the default class that is provided with the class library, as it will not be used in this walkthrough.
From the File menu, choose Save All to save the project.
Constructors control the way your component is initialized; the Finalize method controls the way it tears down. Code in the constructor and the Finalize method of the CDemo class maintains a running count of the number of CDemo objects in existence.
To add code for the constructor and finalizer of the CDemo class
In the Code Editor, add member variables to keep a running total of instances of the CDemo class, and an ID number for each instance.
Public ReadOnly InstanceID As Integer Private Shared NextInstanceID As Integer = 0 Private Shared ClassInstanceCount As Long = 0
Because the InstanceCount and NextInstanceID member variables are declared Shared, they exist only at the class level. All instances of CDemo that access these members will use the same memory locations. Shared members will be initialized the first time the CDemo class is referred to in code. This could be the first time a CDemo object is created, or the first time one of the shared members is accessed.
Locate Public Sub New() and Public Sub New(Container As System.ComponentModel.IContainer), the default constructors for the CDemo class. In Visual Basic, all constructors are named New. Your component can have several constructors, with different parameters, but they must all have the name New.
The access level of the constructors determines what clients will be able to create instances of the class. In other versions of Visual Basic, object creation was controlled by the Instancing property; if you've used the Instancing property, you may find it useful to read Component Instancing Changes in Visual Basic.
Add the following code to Sub New(), to increment the instance count when a new CDemo is created, and to set the instance ID number.
Always add your code after the call to InitializeComponent. At that point, any constituent components have been initialized.
InstanceID = NextInstanceID NextInstanceID += 1 ClassInstanceCount += 1
As a ReadOnly member, InstanceID can be set only in the constructor.
Users familiar with multithreading will point out quite rightly that assigning InstanceID and incrementing NextInstanceID should be an atomic operation. This and other issues related to threading are illustrated in Walkthrough: Authoring a Simple Multithreaded Component with Visual Basic.
Add the following method after the end of the constructor:
Protected Overrides Sub Finalize() ClassInstanceCount -= 1 End Sub
The memory manager calls Finalize just before it finally reclaims memory occupied by the CDemo object. The Finalize method originates with Object, the root of all reference types in the .NET class hierarchy. By overriding Finalize, you can perform cleanup just before your component is removed from memory. However, as you'll see later in this walkthrough, there are good reasons to release resources earlier.
The CDemo class has only one property, a shared property that allows the client to find out how many CDemo objects there are in memory at any given time. Methods can be created in a similar way.
To create a property for the CDemo class
Add the following property declaration to the CDemo class, to allow clients to retrieve the number of instances of CDemo.
Public Shared ReadOnly Property InstanceCount() As Long Get Return ClassInstanceCount End Get End Property
Property declaration syntax is different from that employed in earlier versions of Visual Basic. For more information of the syntax change, see Property Procedure Changes for Visual Basic 6.0 Users.
To test the component, you need a project that uses it. This project must be the first project that starts when you press the Run button.
To add the CDemoTest client project as the startup project for the solution
From the File menu, point to Add and choose New Project to open the Add New Project dialog box.
Select the Windows Application project template, and type CDemoTest in the Name box and then click OK.
In Solution Explorer, right-click CDemoTest and click Set as Startup Project on the shortcut menu.
In order to use the CDemo component, the client test project must have a reference to the class library project. After adding the reference, it is a good idea to add an Imports statement to the test application to simplify use of the component.
To add a reference to the class library project
In the Solution Explorer, click the Show All Files button. Right-click the References node immediately beneath CDemoTest, and select Add Reference from the shortcut menu.
In the Add Reference dialog box, select the Projects tab.
Double-click the CDemoLib class library project. CDemoLib will appear under the References node for the CDemoTest project.
In Solution Explorer, right-click Form1.vb and select View Code from the shortcut menu.
Adding the reference to CDemoLib allows you to use the fully qualified name of the CDemo component — that is, CDemoLib.CDemo.
To add an Imports statement
Add the following Imports statement to the top of the Code Editor for Form1, above the Class declaration:
Adding the Imports statement allows you to omit the library name, and refer to the component type as CDemo. For more information on the Imports statement, see Namespaces in Visual Basic.
You will now create and use a test program to test your component.
The CDemoTest program will illustrate object lifetime in the .NET Framework by creating and releasing large numbers of CDemo objects.
To add code to create and release CDemo objects
Click Form1.vb[Design] to return to the designer.
The nonvisual Timer component appears on a separate design surface below the form.
Double-click the icon for Timer1 to create an event-handling method for the Timer1 component's Tick event. Place the following code in the event-handling method.
Me.Text = "CDemo instances: " & CDemo.InstanceCount
On every tick of the timer, the form's caption will display the current instance count for the CDemo class. The class name is used as a qualifier for the shared InstanceCount property — there is no need to create an instance of CDemo to access a shared member.
Click the Form1.vb [Design] tab to return to the designer.
Right-click Timer1 and select Properties from the shortcut menu. In the Properties window, set the value of its Enabled property to True. This will start the timer as soon as the form is created.
Dim cd As CDemo Dim ct As Integer For ct = 1 To 1000 cd = New CDemo Next
This code may look strange to you. As each instance of CDemo is created, the previous instance is released. When the For loop is done, there will be only one instance of CDemo left. When the event-handling method exits, even that instance will be released, because the variable cd will go out of scope.
As you may have guessed already, things won't happen quite that way.
To run and debug the CDemoTest and CDemo projects
Press F5 to start the solution.
The client project will start, and Form1 will be displayed. Notice that the caption of the form displays "CDemo instances: 0".
Click the button. The caption of the form should display "CDemo instances: 1000".
The instances of CDemo were all released by the time the button's Click event-handling procedure finished. Why haven't they been finalized? In brief, the memory manager finalizes objects in the background, at low priority. The priority is only bumped up if the system gets low on memory. This lazy garbage collection scheme allows for very fast object allocation.
Click the button several more times, watching the caption. At some point, the number of instances will suddenly drop. This means that the memory manager has reclaimed the memory of some of the objects.
If you've clicked more than 10 times, and the number of CDemo instances has not decreased, you may need to adjust the code so that it uses more memory. Close the form to return to the development environment, and increase the number of iterations in the For loop to 10000. Then run the project again.
Repeat step 3. You will get farther this time before the memory manager finalizes more objects.
In fact, each time you repeat step 3, you will probably be able to allocate more CDemo objects before the memory manager steps in. This is because more and more of Visual Studio is swapped out, leaving more space for instances of CDemo.
Close the form to return to the development environment.