Building a Class

function OpenWin(url, w, h) { if(!w) w = 400; if(!h) h = 300; window.open(url, "_new", "width=" + w + ",height=" + h + ",menubar=no,toobar=no,scrollbars=yes", true); } function Print() { window.focus(); if(window.print) { window.print(); window.setTimeout('window.close();',5000); } }
Team-Fly    

Special Edition Using Microsoft® Visual Basic® .NET
By Brian Siler, Jeff Spotts
Table of Contents
Chapter 9.  Creating Code Components


The easiest way to learn is by doing, so let's create a sample class. This sample class module will define a new type whose purpose is to contain employee information. After setting up the class itself, you will learn how to expose properties, methods, and events to its user.

Starting a New Class Library Project

Begin by creating a new project in Visual Basic .NET. Select Class Library from the list of templates available, and name the project MyClasses. Click OK to create a class library project named MyClasses. Notice that the Solution Explorer window contains a file named Class1.vb; this file will contain the code that defines your new class.

Note

You can include multiple classes in a Class Library project by choosing Project, Add Class from the menu system. For simplicity's sake, our sample program will only include a single class.


After the new class has been created, you should give it a unique and descriptive name. The name of a class module is much more significant than the name of a standard code module because you actually use the class name within program code. Many developers like to use the letter c or cls to indicate a class name. This simple class example will be an employee class, so name the class module clsEmployee.

To rename it, go to the Code window for Class1and change the class definition Public Class Class1 to Public Class clsEmployee. Next click Class1.vb in the Solution Explorer window and change its File Name property in the Properties window to clsEmployee.vb.

Now that the infrastructure is complete, this would be a good time to save your project.

The complete MyClasses sample project is available for download on the Internet at www.quepublishing.com.

Adding Properties to the Class

After the class module has been created, you can add your own properties. Properties in your own classes are used in the same way as those of controls, for storing and retrieving information. You can add properties to your class in two ways: by using public variables and property procedures.

Public Variables

Using public variables is the easiest way to create properties. For the sample clsEmployee, you can add a few simple properties with the following code. Type these lines in the Code window just below the Public Class clsEmployee line:

 Public FirstName As String  Public LastName As String  Public DateHired As Date 

Note

Your classes will also usually have several private variables, but only the public variables will be visible to the rest of your application when the object is created.


After you create an object from your class (you will see how shortly), you can use these properties just like those in a custom control:

 MyObject.FirstName = "June"  MyObject.LastName = "Thomas"  MyObject.DateHired = #2/18/1991.htm#  lblEmployeeInfo.Text =  MyObject.FirstName & " " & MyObject.LastName 

One drawback of using public variables for object properties is that no validation is performed on them. In the example, you can assign any values to the FirstName, LastName, and DateHired properties, as long as the value is of the correct type. In addition, public variables return an unprocessed value; you do not have a chance to manipulate the information before returning it.

Property Procedures

Property procedures are more flexible than public variables because they offer the advantage of being able to execute code when someone accesses a property. Property procedures are written like functions; but to users of an object, they behave just like properties. Property procedures provide a way for your users to both retrieve (Get) and assign (Set) the value of a property, and are discussed in detail in Chapter 16, "Creating Your Own Windows Controls."

420

As we mentioned earlier, you can use Public variables to act as simple properties, but no data validation can be done on them. Consider the case of a Salary property. If we were to expose a Salary property as a simple Public variable, we would run into problems if the user attempted to set the value of the Salary property to an unacceptable value, such as a negative number. It would make sense to expose the Salary property as a Property procedure to give us the opportunity to perform some simple data validation.

Let's illustrate by creating the Salary property for our Employee class. The class will contain a private variable named dSalary, in which the employee's salary is stored internally to the class. Users of the class cannot see the dSalary variable directly; instead, it is exposed through the Salary property. The Salary property will consist of a Property procedure with two parts: the Get portion of the procedure contains code that retrieves the value of dSalary and passes it along to the user; the Set portion contains code that accepts the user's input and, if valid, assigns it to the internal dSalary variable.

Set up the internal dSalary variable for the property value by entering the following line of code into the Code window for the clsEmployee class, just below the public variable declarations you entered earlier:

 Private Shared dSalary As Decimal 

To create the Property procedure for the Salary property, type the following line of code into the Code window:

 Public Property Salary() As Decimal 

When you press Enter, a complete Property procedure shell for the Salary property is created, as illustrated in Figure 9.1.

Figure 9.1. Visual Basic .NET creates Property procedure shells automatically.

graphics/09fig01.gif

When creating this procedure shell, Visual Basic .NET adds the framework for the Get and Set portions of the procedure, which will be executed when the user attempts to retrieve or assign, respectively, the value of the property.

When users access the Salary property, the appropriate portion of the property procedure is executed. When the user attempts to retrieve the value of the property, the Get portion of the property procedure reads the value from the internal nSalary private variable and returns it to the user (via the Return keyword). When the user attempts to assign the value of the property, the Set portion of the Property procedure examines the value provided by the user, which is passed into the procedure via the Value parameter, and sets the internal nSalary variable appropriately.

Creating the Salary Property Procedure

The following illustrates the complete Property procedure for the Salary property. Go ahead and enter the code now:

 Public Property Salary() As Decimal      Get          Return dSalary      End Get      Set(ByVal Value As Decimal)          If Value >= 0 Then              dSalary = Value          Else              RaiseEvent DataError("Salary cannot be negative.")          End If      End Set  End Property 
Adding a FullName Property

Adding another property that returns the full name of the employee gives us a chance to demonstrate how some basic code can create a value-added property. Simply put, the FullName property will concatenate the first and last names of the employee (along with a space in the middle) and return the assembled string. Add the FullName Property procedure shown next to the Code window, just below the Salary property:

 ReadOnly Property FullName() As String      Get          Return Trim(FirstName & " " & LastName)      End Get  End Property 

Note that the FullName property is ReadOnly, meaning that the user can retrieve it but not set it. Because of this, there is no need for a Set portion of the Property procedure.

Adding a Department Property

Next, let's add a Department property to the class. Users will be able to set the Department property to a string specifying an employee's department; however, the value will be stored internally as an Integer. The Department property procedure will be responsible for converting between the internal property value and the external representation seen by the user of the class. Set up the internal variable for the property value, which we'll call nDeptNum, by entering the following line of code into the Code window for the clsEmployee class, just below the public variable declarations you entered earlier:

 Private Shared nDeptNum As Integer 
Creating the Department Property Procedure

The following illustrates the complete Property procedure for the Department property. Go ahead and enter the code now:

 Public Property Department() As String      Get          Select Case nDeptNum              Case 1                  Return "Marketing"              Case 2                  Return "Accounting"              Case Else                  Return ""          End Select      End Get      Set(ByVal Value As String)          Select Case Trim(UCase(Value))              Case "MARKETING"                  nDeptNum = 1              Case "ACCOUNTING"                  nDeptNum = 2              Case Else                  nDeptNum = 0          End Select      End Set  End Property 

In the preceding code, the Property procedure actually stores the value representing the employee's department in a private integer variable (nDeptNum). However, users of the object always assign and retrieve a string. In a real-world program, this procedure would probably be more complex, doing things like storing a series of predefined department names in a database and allowing the user to specify a new department name to be added to the database.

Adding a Supervisor Property

We will add one more property that is slightly more interesting. One of the main reasons for creating a class in the first place is to be able to create multiple instances of that class. Consider our Employee class. A program that uses it might need to create an instance for each member of a department. One nice feature would be to add a Supervisor property. Because the supervisor is (presumably) an employee as well, then he or she should be represented by an instance of the Employee class. The Supervisor property will accept another instance of the Employee class as its value. In other words, you don't set the Supervisor property to a String or an Integer; you set it to an Employee class type.

The Supervisor property will be stored internally through a Private variable of the Employee type, much like the Salary property is stored internally in the Private dSalary variable. Add the following declaration in the same area of clsEmployee's Code window as the other declarations:

 Private objSupervisor As clsEmployee 

The Supervisor Property procedure is pretty straightforward. Go ahead and enter it into the Code window now:

 Property Supervisor() As clsEmployee      Get          Return objSupervisor      End Get      Set(ByVal Value As clsEmployee)          objSupervisor = Value      End Set  End Property 

Note

If you try to access the Supervisor property for an instance of clsEmployee whose Supervisor property has not been set, you will get an error. You can get around this by using code like

 If objEmp.Supervisor Is Nothing Then code Else code. 


Adding a Method to the Class

As you know, objects perform actions via methods, such as the Add method of a ListBox control or the Focus method of a Button control. You can create methods in your own classes by adding public procedures or functions to the class module. Public procedures and functions work just like regular procedures and functions, but the Public keyword indicates that they will be visible to users of your object.

To demonstrate the use of a method in our sample Employee class, we will create a ChangeSalary method. This method will accept a single argument, representing the percentage positive or negative by which we want to change an employee's salary.

Enter the following code in the Code window for the Employee class:

 Public Function ChangeSalary(ByVal sngAmt As Decimal)      If (sngAmt > 1) Or (sngAmt < -1) Then          sngAmt = sngAmt / 100      End If      Salary = Salary * (1 + sngAmt)  End Function 

This example gives us the opportunity to demonstrate some rudimentary data validation. Note how the code examines the value of the input argument, sngAmount, to see whether it is in the range 1 to 1. If the value does not fall within that range, which represents 100% to 100%, we assume that the user entered the desired salary change as a percentage number, rather than the decimal equivalent of a percentage. In this case, we will divide the input argument by 100 to convert it to a true decimal amount. In other words, if the user enters 25 with the intention of granting a 25% raise, the argument will be converted to the decimal equivalent of 0.25 to complete the calculation.

Adding an Event to a Class

You have already learned that objects raise events, like when a Button control raises the Click event (in response to a user having clicked the button). Events provide a way for an object to execute code written by the user of the object. The object triggers the event by way of an event handler. You already know how to place code in event handlers. To create an event in your own class, you need to do two things:

  1. Declare the event in the class.

  2. Use the RaiseEvent statement to trigger the event when appropriate.

Let's illustrate this concept by adding a sample DataError event to the Employee class. This event will be available to tell the user that some type of data error has occurred.

Suppose you want to return an error if a user attempts to set the value of the Salary property to a negative number. Simply adding a RaiseEvent statement to the right place in the Salary Property procedure will cause an error to be raised when necessary.

Declaring the Event

Before you can raise an event, you must declare that the event can exist. You do so by using an Event statement, which tells a class the name of an event that might be raised at some point. Type the following line of code near the top of clsEmployee's Code window, just below the variable declarations:

 Public Event DataError(ByVal sErrorMsg As String) 
Raising the Event

Now that you have taught the class that an event may happen, you need to add code to raise the event when appropriate. You will do so by adding an Else clause to the If statement that decided whether the user-supplied value for the Salary property was positive. Modify the Salary property procedure so it looks like this:

 Public Property Salary() As Decimal      Get          Return dSalary      End Get      Set(ByVal Value As Decimal)          If Value >= 0 Then              dSalary = Value          Else              RaiseEvent DataError("Salary cannot be negative.")          End If      End Set  End Property 

Note

A single event can be raised from multiple locations within the class. For example, you might want to replace the Public variable that handles the DateHired property with a true Property procedure, which could check to see whether the date supplied was reasonable (for example, dates in the future may not be acceptable). When an invalid date is detected, you could use code such as RaiseEvent DataError("Invalid Date Hired").


The Life Cycle of Your Class

When working with custom classes, you might need to be concerned about what happens when instances of the class are created, and what happens when they are no longer needed. These can be handled by working with the class' constructors and finalizers.

Constructors

The term constructor refers to the procedure that executes when an instance of a class is created. You can write code in the constructor procedure to control what happens. For example, you may want to keep track of how many instances of a class are currently active. Although this is not particularly useful for the Employee class, we will demonstrate how to accomplish this.

Add the following declarations after the other declaration statements near the top of the Code window:

 Public Shared ClassInstanceCount As Long = 0  Private Shared NextInstanceID As Integer = 1  Public ReadOnly InstanceID As Integer 

This sets up the following three variables:

Variable

Purpose

ClassInstanceCount

Keeps track of how many instances of clsEmployee are alive. As a Shared variable, it exists only at the class level; therefore, each instance of clsEmployee sees the same copy of ClassInstanceCount. As a Public variable, it will serve as a quasi-property reporting how many instances of clsEmployee are alive.

NextInstanceID

A Private variable used internally to hold the value to be assigned to the InstanceID variable for the next instance to be created.

InstanceID

A Public variable acting as a property, InstanceID reports the ID of the current instance of clsEmployee.

The default constructor for the clsEmployee class is the Sub New procedure, which executes each time an instance of clsEmployee is created, and does not yet exist in our sample application. To create and display the shell of the Sub New procedure, select New from the Method Name box in the Code window. Add the following code to Sub New:

 Public Sub New()      InstanceID = NextInstanceID      NextInstanceID += 1      ClassInstanceCount += 1  End Sub 

As you can see, this code sets the value of the InstanceID property to the next available value (as determined by the value of NextInstanceID), then increments NextInstanceID, and finally increments the ClassInstanceCount counter, which keeps track of how many copies of the class are alive.

You can place in the Sub New constructor any other code that you need to execute when a new instance of your class is created. For example, you might want to set some internal values,such as the date the instance was created; write information to a database; or ensure that any dependent classes are loaded.

Finalizers

A class' finalizer, which is code executed by the Finalize event handler, is invoked just before an instance of that class is destroyed. This gives you a chance to do any housekeeping necessary to clean up.

To access the Finalize event handler of your class, choose Finalize from the Method Name box in the Code window. Note that one line of code (MyBase.Finalize) is placed in the procedure already. After that line, add the following:

 ClassInstanceCount -= 1 

This decrements the counter that keeps track of how many copies of the class are alive.

The Complete Code

Listing 9.1 shows the complete code for the clsEmployee class.

Listing 9.1 MYCLASSES.ZIP The Complete Code Listing for the clsEmployees Class
 Public Class clsEmployee      Public FirstName As String      Public LastName As String      Public DateHired As Date      Private dSalary As Decimal      Private nDeptNum As Integer      Private objSupervisor As clsEmployee      Public Shared ClassInstanceCount As Long = 0      Private Shared NextInstanceID As Integer = 1      Public ReadOnly InstanceID As Integer      Public Event DataError(ByVal sErrorMsg As String)      Public Property Salary() As Decimal          Get          Return dSalary      End Get      Set(ByVal Value As Decimal)          If Value >= 0 Then              dSalary = Value          Else              RaiseEvent DataError("Salary cannot be negative.")          End If      End Set  End Property  ReadOnly Property FullName() As String      Get          Return Trim(FirstName & " " & LastName)      End Get  End Property  Public Property Department() As String      Get          Select Case nDeptNum              Case 1                  Return "Marketing"              Case 2                  Return "Accounting"              Case Else                  Return ""          End Select      End Get      Set(ByVal Value As String)          Select Case Trim(UCase(Value))              Case "MARKETING"                  nDeptNum = 1              Case "ACCOUNTING"                  nDeptNum = 2              Case Else                  nDeptNum = 0          End Select      End Set  End Property  Property Supervisor() As clsEmployee      Get          Return objSupervisor      End Get      Set(ByVal Value As clsEmployee)          objSupervisor = Value      End Set  End Property  Public Function ChangeSalary(ByVal sngAmt As Decimal)      If (sngAmt > 1) Or (sngAmt < -1) Then          sngAmt = sngAmt / 100      End If      Salary = Salary * (1 + sngAmt)  End Function      Public Sub New()          InstanceID = NextInstanceID          NextInstanceID += 1          ClassInstanceCount += 1      End Sub      Protected Overrides Sub Finalize()          MyBase.Finalize()          ClassInstanceCount -= 1      End Sub  End Class 

    Team-Fly    
    Top
     



    Special Edition Using Visual Basic. NET
    Special Edition Using Visual Basic.NET
    ISBN: 078972572X
    EAN: 2147483647
    Year: 2001
    Pages: 198

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net