Classes

Team-Fly    

 
Application Development Using Visual Basic and .NET
By Robert J. Oberg, Peter Thorsteinson, Dana L. Wyatt
Table of Contents
Chapter 3.  VB.NET Essentials, Part I


In this section we carefully examine the VB.NET class , which is fundamental to programming in VB.NET. For illustration we introduce two classes, Customer and Hotel , which will be elaborated in a case study that is used throughout the book. We will introduce the case study itself in Chapter 5.

Classes as Structured Data

VB.NET defines primitive data types that are built into the language. Data types, such as Integer and Decimal , can be used to represent simple data. VB.NET provides the class mechanism to represent more complex forms of data. Through a class, you can build up structured data out of simpler elements, which are called data members , or fields . (See TestCustomer\Step0 .)

 graphics/codeexample.gif ' Customer.vb  - Step 0 (same as Step 1) Public Class Customer    Public CustomerId As Integer    Public FirstName As String    Public LastName As String    Public EmailAddress As String    Public Sub New(_     ByVal first As String, _     ByVal last As String, _     ByVal email As String)       FirstName = first       LastName = last       EmailAddress = email    End Sub End Class 

Customer is now a new data type. A Customer class object has a CustomerId , a FirstName , a LastName , and an EmailAddress .

Classes and Objects

A class represents a "kind of," or type of, data. It is somewhat analogous to the built-in types like Integer and Decimal . A class can be thought of as a template from which individual instances can be created. An instance of a class is called an object. The fields, such as CustomerId and FirstName in our example, are sometimes also called instance variables .

References

There is a fundamental distinction between the primitive data types, such as Integer , and the extended data types that can be created using classes. When you declare a variable of a primitive data, you are allocating memory and creating the actual instance. This is because the variable itself contains its own data value.

 Dim x as Integer '4 bytes of memory have been allocated 

When you declare a variable of a class type (an object reference ), you are only obtaining memory for a reference to an object of the class type. No memory is allocated for the object itself, which may be quite large. This behavior is identical to what happens in Java.

 'cust is a reference to a Customer object Dim cust As Customer ' The object itself does not yet exist 
Constructors

Through a constructor, you can initialize individual objects in any way you wish. Besides initializing instance data, you can perform other appropriate initializations (e.g., open a file).

A constructor is like a special method that is automatically called when an object is created via the New keyword. A constructor

  • has no return type (i.e., a subroutine)

  • has the name New

  • should usually have public access

  • may take parameters, which are passed when invoking New

You use the New keyword to instantiate object instances, and you pass desired values as parameters.

Default Constructor

If you do not define a constructor in your class, VB.NET will implicitly create one for you. It is called the default constructor and takes no arguments. The default constructor will assign instance data, using any assignments in the class definition. Fields without an initializer are assigned default values (0 for numerical data types, empty string for String , and so on.) The default constructor is called when an object instance is created with New and no parameters. If you provide code for any constructor in your class, you must explicitly define a default constructor with no arguments, if you want one.

Instantiating and Using an Object

You instantiate an object by the New operator, which will cause a constructor to be invoked.

 cust = New Customer(_    "Rocket", _    "Squirrel", _    "rocky@frosbitefalls.com") ' Customer object now exists and cust is a reference to it 

Once an object exists, you work with it, including accessing its fields and methods . Our simple Customer class at this point has no methods, only four fields. You access fields and methods using a dot.

  cust.CustomerId  = 1 ' all fields have now been assigned 

TestCustomer\Step0 provides a simple test program to exercise the Customer class. Note that an unassigned field of a class receives a default value, such as 0, when an object is instantiated .

Assigning Object References

TestCustomer\Step1 provides a more complete test program to exercise the Customer class. Two object instances are created, an assignment is made of one object reference to another, and a field is assigned a value.

 graphics/codeexample.gif ' TestCustomer.vb - Step1 Imports System Module TestCustomer    Public Sub Main()       Dim cust1, cust2 As Customer       cust1 = New Customer(_          "Rocket", _          "Squirrel", _          "rocky@frosbitefalls.com")       cust1.CustomerId = 1       cust2 = New Customer(_          "Bullwinkle", _          "Moose", _          "moose@wossamotta.edu")       cust2.CustomerId = 2       ShowCustomer("cust1", cust1)       ShowCustomer("cust2", cust2)       cust1 = cust2 ' cust1, cust2 refer to same object       cust1.EmailAddress = "bob@podunk.edu"       ShowCustomer("cust1", cust1)       ShowCustomer("cust2", cust2)    End Sub    Private Sub ShowCustomer(_     ByVal label As String, ByVal cust As Customer)       Console.WriteLine("---- {0} ----", label)       Console.WriteLine(_          "CustomerId = {0}", cust.CustomerId)       Console.WriteLine(_          "FirstName = {0}", cust.FirstName)       Console.WriteLine(_          "LastName = {0}", cust.LastName)       Console.WriteLine(_          "EmailAddress = {0}", cust.EmailAddress)    End Sub End Module 

Figure 3-9 shows the object references cust1 and cust2 and the data they refer to after the objects have been instantiated and the CustomerId field has been assigned.

Figure 3-9. Two object references and the data they refer to.

graphics/03fig09.gif

When you assign an object variable, you are assigning only the reference; there is no copying of data . [3] Figure 3-10 shows both object references and their data after the assignment:

[3] C and C++ programmers will recognize assignment of references as similar to assignment of pointers.

Figure 3-10. Two references refer to the same data.

graphics/03fig10.gif

 cust1 = cust2 ' cust1, cust2 refer to same object 

Now consider what happens when you assign a new value to a field of one object,

 cust1.EmailAddress = "bob@podunk.edu" 

You will now see the same data through both object references, since they refer to the same object. Here is the output from running TestCustomer\Step1 .

 ---- cust1 ---- CustomerId = 1 FirstName = Rocket LastName = Squirrel EmailAddress = rocky@frosbitefalls.com ---- cust2 ---- CustomerId = 2 FirstName = Bullwinkle LastName = Moose EmailAddress = moose@wossamotta.edu ---- cust1 ---- CustomerId = 2 FirstName = Bullwinkle LastName = Moose EmailAddress = bob@podunk.edu ---- cust2 ---- CustomerId = 2 FirstName = Bullwinkle LastName = Moose EmailAddress = bob@podunk.edu 
Garbage Collection

Through the assignment of a reference, an object may become orphaned. Objects may also be orphaned when they pass out of scope (i.e., when a local reference variable is lost as the method it is declared in returns). Such an orphan object (or "garbage") takes up memory in the computer, which can now never be referenced. In Figure 3-2 the customer with CustomerId of 1 is now garbage.

The CLR automatically reclaims the memory of unreferenced objects. This process is known as garbage collection . Garbage collection takes up some execution time, but it is a great convenience for programmers, helping to avoid a common program error known as a memory leak . [4] Garbage collection is discussed in more detail in Chapter 10.

[4] Memory leaks have always plagued C and C++ programmers, but languages such as VB.NET, previous versions of Visual Basic, and Java have been spared this nightmare.

Methods

Typically, a class will specify behavior as well as data. A class encapsulates data and behavior in a single entity. A method specifies the behavior and consists of either a Function or a Sub defined within the class, with the following characteristics:

  • An optional access specifier , typically Public or Private

  • A return type for a Function , (a Sub is used if no data is returned)

  • A method name, which can be any legal VB.NET identifier

  • A parameter list, enclosed by parentheses, which specifies data that is passed to the method (can be empty if no data is passed)

  • A method body, enclosed by Function and End Function or Sub and End Sub , which contains the code that the method will execute

Here is an example of a method in the Hotel class taken from the Hotel.vb source file in the TestHotel\Step1 example.

 graphics/codeexample.gif Public Sub  RaisePrice  (ByVal amount As Decimal)    rate += amount End Sub 

In this example there is no data returned, so it is implemented with a Sub . The method name is RaisePrice , the parameter list consists of a single parameter of type Decimal , and the body contains one line of code that increments the member variable rate by the value that is passed in as a parameter.

Public and Private

Fields and methods of a VB.NET class can be specified as Public or Private . Normally, you declare fields as Private . A private field can be accessed only from within the methods defined in the same class, not from outside the class.

 Public Class Hotel  Private city As String   Private name As String   Private number As Integer = 50   Private rate As Decimal  ... 

Note that in VB.NET you can initialize fields where they are declared, as shown in the case of the field named number .

Methods may be declared as either Public or Private . Public methods can be called from outside of the class and are often used to perform calculations and to manipulate private field data. You may also provide public "accessor" methods to provide access to private fields.

 ...  Public Function GetRate() As Decimal  Return rate End Function  Public Sub SetRate(ByVal val As Decimal)  rate = val End Sub ... 

You may also have private methods, which can be thought of as helper functions for use within the class. Rather than duplicating code in several places, you may create a private method, which will be called wherever it is needed internally. An example is the ShowHotel method in TestHotel.vb .

The Keyword Me

Sometimes it is convenient within code for a method to be able to access the current object reference. VB.NET defines the keyword Me (similar to the keyword this in C++, Java, and C#), which is a special variable that always refers to the current object instance. With Me you can then refer to the instance variables, but usually, you can simply refer to them directly without using Me explicitly. The Hotel class has a constructor to initialize its instance data with values passed as parameters. We can make use of the same names for parameters and fields and remove ambiguity by using the Me variable explicitly. Here is the code for the Hotel constructor:

 Public Sub New(_ ByVal city As String, _ ByVal name As String, _ ByVal number As Integer, _ ByVal rate As Decimal)  Me  .city = city  Me  .name = name  Me  .number = number  Me  .rate = rate End Sub 
Sample Program

The program TestHotel\Step1 illustrates all the features we have discussed so far. Here is the class definition:

 graphics/codeexample.gif ' Hotel.vb - Step 1 Public Class Hotel    Private city As String    Private name As String    Private number As Integer = 50    Private rate As Decimal    Public Sub New(_     ByVal city As String, _     ByVal name As String, _     ByVal number As Integer, _     ByVal rate As Decimal)       Me.city = city       Me.name = name       Me.number = number       Me.rate = rate    End Sub    Public Sub New()    End Sub    Public Function GetCity() As String       Return city    End Function    Public Function GetName() As String       Return name    End Function    Public Function GetNumber() As Integer       Return number    End Function    Public Sub SetNumber(ByVal val As Integer)       number = val    End Sub    Public Function GetRate() As Decimal       Return rate    End Function    Public Sub SetRate(ByVal val As Decimal)       rate = val    End Sub    Public Sub RaisePrice(ByVal amount As Decimal)       rate += amount    End Sub End Class 

Here is the test program:

 ' TestHotel.vb - Step 1 Imports System Module TestHotel    Sub Main()       Dim generic As Hotel = New Hotel()       ShowHotel(generic)       Dim ritz As Hotel = New Hotel(_          "Atlanta", "Ritz", 100, 95D)       ShowHotel(ritz)       ritz.RaisePrice(50D)       ritz.SetNumber(125)       ShowHotel(ritz)    End Sub    Private Sub ShowHotel(ByVal hotel As Hotel)       Console.WriteLine(_          "{0} {1}: number = {2}, rate = {3:C}", _          hotel.GetCity(), hotel.GetName(), _          hotel.GetNumber(), hotel.GetRate())    End Sub End Module 

Here is the output:

 : number = 50, rate = 
 : number = 50, rate = $0.00 Atlanta Ritz: number = 100, rate = $95.00 Atlanta Ritz: number = 125, rate = $145.00 
.00 Atlanta Ritz: number = 100, rate = .00 Atlanta Ritz: number = 125, rate = 5.00

Properties

The encapsulation principle leads us to typically store data in private fields and to provide access to this data through public accessor methods that allow us to set and get values. For example, in the Hotel class we provide a method GetCity to access the private field city . You don't need any special syntax; you can simply provide methods and call these methods what you want, typically GetXXX and SetXXX .

VB.NET provides a special property syntax that simplifies client code. You can access a private field as if it were a public member. Here is an example of using the Number property of the Hotel class.

  ritz.Number  = 125 Console.WriteLine(_    "There are now {0} rooms",  ritz.Number  ) 

As you can see, the syntax using the property is a little more concise . Properties were popularized in Visual Basic and are now part of .NET and available in selected other .NET languages, such as C# and managed C++. The program TestHotel\Step2 illustrates implementing and using several properties, City , Name , Number and Rate . The first two properties are read-only (only Get defined), and the other properties are read/write (both Get and Set ). It is also possible to have a write-only property (only Set defined). Here is the code for the properties Name (read-only) and Number (read-write) in the second version of the Hotel class. Notice the syntax and the VB.NET keyword Value to indicate the new value of the field. The private fields are now spelled with an "m_" prefix (short for member variable) to distinguish them from the corresponding property names, preventing a compiler error.

 graphics/codeexample.gif ' Hotel.vb - Step 2 Public Class Hotel    Private m_City As String    Private m_Name As String    Private m_Number As Integer    Private m_Rate As Decimal    ...  Public ReadOnly Property Name() As String   Get   Name = m_Name   End Get   End Property   Public Property Number() As Integer   Get   Number = m_Number   End Get   Set(ByVal Value As Integer)   m_Number = Value   End Set   End Property   ..  . 

Shared Fields and Methods

In VB.NET, a field normally is defined on a per-instance basis, with a unique value for each object instance of the class. Sometimes it is useful to have a single value associated with the entire class as a whole. This type of field is called a Shared field, or a class variable as opposed to an instance variable. Like instance data members, shared data members can be either Public or Private . To access a public shared member, you use the dot notation, but in place of an object reference before the dot, you use the name of the class.

Shared Methods

A method may also be declared as Shared . A shared method can be called without instantiating the class. If you declare the Main method in a module, you do not declare it as shared, since all methods in a module are inherently shared; however, if you declare a Main method in a class, you must declare it as shared. This allows the runtime system to call Main without instantiating an object.

You call a shared method by using the dot notation, with the class name in front of the dot. You can call a shared method without an instance, and a shared method can only access shared data members and not instance data members.

Shared methods may be declared Public or Private . A private shared method, like other private methods, may be used as a helper function within a class, but not called from outside the class.

Sample Program

Our previous Customer class relied on the user of the class to assign a CustomerId for the customer. A better approach is to encapsulate the assignment of this field within the class itself, so that a unique ID will be automatically generated every time a new Customer object is created. It is easy to implement such a scheme by using a shared field nextCustId , which is used to assign a new ID. Every time the ID is assigned, nextCustId is incremented. TestCustomer\Step2 demonstrates this solution and also illustrates the use of a shared method. Here is the code defining the Customer class:

 graphics/codeexample.gif ' Customer.vb - Step 2 Public Class Customer    Public CustomerId As Integer    Public FirstName As String    Public LastName As String    Public EmailAddress As String  Private Shared nextCustId As Integer = 1  Public Sub New(_     ByVal first As String, _     ByVal last As String, _     ByVal email As String)       CustomerId = nextCustId       nextCustId += 1       FirstName = first       LastName = last       EmailAddress = email    End Sub  Public Shared Function GetNextId() As Integer   Return nextCustId   End Function  End Class 

Here is the test program:

 ' TestCustomer.vb - Step 2 Imports System Module TestCustomer    Sub Main()       Console.WriteLine("next id = {0}", _       Customer.GetNextId())       Dim cust1, cust2 As Customer       cust1 = new Customer("John", "Doe", _          "john@rocky.com")       cust2 = new Customer("Mary", "Smith", _          "mary@moose.edu")       ShowCustomer("cust1", cust1)       ShowCustomer("cust2", cust2)    End Sub    Private Sub ShowCustomer(_     ByVal label As String, ByVal cust As Customer)    ... 

Note that the shared method GetNextId is accessed through the class Customer and not through an object reference such as cust1 . Note the fact that Main is an implicitly shared method, since it is a member of a module, and is invoked by the runtime without an instance of an object being created. Here is the output from the program:

 next id = 1 ---- cust1 ---- CustomerId = 1 FirstName = John LastName = Doe EmailAddress = john@rocky.com ---- cust2 ---- CustomerId = 2 FirstName = Mary LastName = Smith EmailAddress = mary@moose.edu 

Shared Constructor

Besides having shared fields and shared methods, a class may also have a shared constructor . A shared constructor is called only once, before any object instances have been created. A shared constructor is defined by prefixing the constructor with Shared . A shared constructor must take no parameters and has no access modifier (such as Public or Private ).

In some languages, such as C++, where there can be global variables not attached to any class, you may initialize a library through the constructor for a global object. In VB.NET there are no such freestanding global objects, but you can achieve similar initialization through use of a shared constructor. As a somewhat whimsical example of a shared constructor, consider the SharedWorld program, which provides an alternative implementation of "Hello, World." This program displays the text Hello, World, proving that the shared constructor automatically executes first, displaying the text Hello, . Then later, the call to the World method displays the word World.

 graphics/codeexample.gif ' SharedWorld.vb Public Class Hello  Shared Sub New()  System.Console.Write("Hello, ")    End Sub    Public Shared Sub World()       System.Console.WriteLine("World")    End Sub End Class Module Module1    Sub Main()       Hello.World()    End Sub End Module 

Constant and Read Only Fields

If you want to make sure that a variable or field always has the same value, you can assign the value via an initializer and use the Const modifier. After its one-time initialization at runtime, the value cannot be changed. You can also define a field or property to be ReadOnly , with the same effect.

The program ConstantHotel illustrates the use of both Const and Read-Only . In both cases, you will get a compiler error if you try to modify the value after it has been initialized .

 graphics/codeexample.gif ' ConstantHotel.vb Public Class Hotel  Public Const rate As Decimal = 100D   Public ReadOnly name As String  Public Sub New(ByVal name As String)       Me.name = name    End Sub End Class 

Here is the test program:

 ' TestHotel.vb Imports System Module TestHotel    Sub Main()       Dim Hotel As Hotel = New Hotel("Ritz")       Console.WriteLine("rate = {0:C}", Hotel.rate)  '   Hotel.rate = 150D       // illegal  Console.WriteLine("hotel name = {0}", Hotel.name)  '   hotel.name = "Sheraton" // illegal  End Sub End Module 

Here is the output:

 rate = 0.00 hotel name = Ritz 

Team-Fly    
Top
 


Application Development Using Visual BasicR and .NET
Application Development Using Visual BasicR and .NET
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 190

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