Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(ebook) Visual Studio .NET Mastering Visual Basic.pdf
Скачиваний:
120
Добавлен:
17.08.2013
Размер:
15.38 Mб
Скачать

BUILDING THE MINIMAL CLASS 335

Every time you create a new variable of the Minimal type, you’re creating a new instance of the Minimal class. The class’s code is loaded into memory only the first time you create a variable of this type, but every time you declare another variable of the same type, a new set of variables is created. This is called an instance of the class. The code is loaded once, but it can act on different sets of variables. In effect, different instances of the class are nothing more than different sets of local variables.

The New Keyword

The New keyword tells VB to create a new instance of the Minimal class. If you omit the New keyword, you’re telling the compiler that you plan to store an instance of the Minimal class in the obj variable, but the class won’t be instantiated. You must still initialize the obj variable with the New keyword on a separate line:

obj = New Minimal()

If you omit the New keyword, a “Null Reference” exception will be thrown when the code attempts to use the variable. This means that the variable is Null—it hasn’t been initialized yet.

Property Procedures

The property1 and property2 properties will accept any value, as long as the type is correct and the value of the numeric property is within the acceptable range. But what if the generic properties were meaningful entities, like ages or zip codes? We should be able to invoke some code to validate the values assigned to the property. To do so, you must implement the properties with the so-called Property procedures.

Properties are implemented with a special type of procedure that contains a Get and Set section. The Set section of the procedure is invoked when the application attempts to set the property’s value, and the Get section is invoked when the application requests the property’s value. Usually, the value passed to the property is validated in the Set section and, if valid, stored to a local variable. The same local variable’s value is returned to the application when it requests the property’s value, from the property’s Get section. Listing 8.3 shows what the implementation of an Age property would look like.

Listing 8.3: Implementing Properties with Property Procedures

Private tAge As Integer

Property Age() As Integer

Get

Age = tAge

End Get

Set (ByVal Value As Integer)

If Value < 0 Or Value >= 125 Then

MsgBox(“Age must be positive and less than 125”)

Else

tAge = Value

End If

End Set

End Property

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

336 Chapter 8 BUILDING CUSTOM CLASSES

tAge is the local variable where the age is stored. When a line like the following is executed in the application that uses your class, the Set section of the Property procedure is invoked:

obj.Age = 39

Since the value is valid, it’s stored in the tAge local variable. Likewise, when a line like the following one is executed,

Console.WriteLine(obj.Age)

the Get section of the Property procedure is invoked, and the value 39 is returned to the application. The Value keyword in the Set section represents the actual value that the calling code is attempting to assign to the property. You don’t declare this variable, and its name is always Value. The tAge variable is declared as private, because we don’t want any code outside the class to access it; this variable is used by the class to store the value of the Age property and can’t be manipulated directly. The

Age property is, of course, public, so that other applications can set it.

Enter the Property procedure for the Age property in the Minimal class and then switch to the form to test it. Open the Button’s Click event handler and add the following lines to the existing ones:

obj.Age = 39

Console.WriteLine(“after setting the age to 39, age is “ & obj.Age.ToString) obj.Age = 199

Console.WriteLine(“after setting the age to 199, age is “ & obj.Age.ToString)

The value 39 will appear in the Output window. This means that the class accepted the value 39. When the third statement is executed, a message box will appear with the error’s description:

Age must be positive and less than 125

then the value 39 will appear again in the Output window again. The attempt to set the age to 199 failed, so the property retains its previous value.

Raising Exceptions

Our error-trapping code works fine, but what good is it? Any developer using our class won’t be able to handle this error. You don’t want to display messages from within your class, because messages are intended for the final user. As a developer, you’d rather receive an exception and handle it from within your code. So, let’s change the implementation of the Age property a little. The Property procedure for the Age property (Listing 8.4) throws an argument exception if you attempt to assign an invalid value to it.

Listing 8.4: Throwing an Exception from within a Property Procedure

Private tAge As Integer

Property Age() As Integer

Get

Age = tAge

End Get

Set (ByVal Value As Integer)

If Value < 0 Or Value >= 125 Then

Dim AgeException As New ArgumentException()

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

BUILDING THE MINIMAL CLASS 337

Throw AgeException

Else

tAge = Value

End If

End Set

End Property

You can test this property in your application; switch to the test form, and enter the statements of Listing 8.5 in a new button’s Click event handler (this is the code behind the Handle Exceptions button on the test form).

Listing 8.5: Catching the Age Property’s Exception

Dim obj As New Minimal() Dim userAge as Integer

UserAge = InputBox(“Please enter your age”) Try

obj.Age = userAge

Catch exc as ArgumentException

MsgBox(“Can’t accept your value, “ & userAge.ToString & VbCrLf & _ “Will continue with default value of 30”)

obj.Age = 30 End Try

This is a much better technique for handling errors in your class. The exceptions can be intercepted by the calling application, and developers using your class can write a robust application by handling the exceptions in their code. When you develop custom classes, keep in mind that you can’t handle most errors from within your class, because you don’t know how other developers will use your class. Make your code as robust as you can, but don’t hesitate to throw exceptions for all conditions you can’t handle from within your code (Figure 8.3). Our example continues with a default age of 30. But as a class developer, you can’t make this decision—another developer might prompt the user for another value, and a sloppy developer might let his application crash (but this isn’t your problem).

Figure 8.3

Raising an exception in the class’s code

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

338 Chapter 8 BUILDING CUSTOM CLASSES

Implementing Read-Only Properties

Let’s make our class a little more complicated. Age is not usually requested on official documents. Instead, you must furnish your date of birth, from which your current age can be calculated at any time. We’ll add a BDate property in our class and make Age a read-only property.

To make a property read-only, you simply declare it as ReadOnly and supply the code for the Get procedure only. Revise the Age property’s code in the Minimal class as seen in Listing 8.6. Then enter the Property procedure from Listing 8.7 for the BDate property.

Listing 8.6: Making a Read-Only Property

Private tAge As Integer

ReadOnly Property Age() As Integer

Get

Age = tAge

End Get

End Property

Listing 8.7: The BDate Property

Private tBDate As Date

Property BDate() As Date Get

BDate = tBDate End Get

Set

If Not IsDate(Value) Then MsgBox(“Invalid date”) Exit Property

End If

If Value > Now() Or DateDiff(DateInterval.Year, Now(), Value) >= 125 Then MsgBox(“Age must be positive and less than 125”)

Else

tBDate = Value End If

End Set

End Property

The code calls the DateDiff() function, which returns the difference between two dates in a specified interval—in our case, years. The expression DateInterval.Year is the name of constant, which tells the DateDiff() function to calculate the difference between the two dates in years. You don’t have to memorize the constant names—you simply select them from a list as you type.

So, the code checks the number of years between the date of birth and the current date. If it’s negative (which means that the person hasn’t been born yet) or more than 125 years (just in case), it rejects the value. Otherwise it sets the value of the tBDate local variable.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

BUILDING THE MINIMAL CLASS 339

Now we must do something about the Age property’s value. The implementation of the Age property shown in Listing 8.6 allows you to read the value of the property, but not set it. However, you must update the tAge variable. Instead of maintaining a local variable for the age, we can calculate it every time the user requests the value of the Age property. Revise the Age property’s code to match Listing 8.8, so that it calculates the difference between the date of birth and the current date and returns the person’s age.

Listing 8.8: A Calculated Property

ReadOnly Property Age() As Integer

Get

Age = CInt(DateDiff(DateInterval.Year, Now(), tBDate))

End Get

End Property

Notice also that you no longer need the tAge local variable, because the age is calculated on-the-fly when requested. As you can see, you don’t always have to store property values to local variables. A property that returns the number of files in a directory, for example, also doesn’t store its value in a local variable. It retrieves the requested information on-the-fly and furnishes it to the calling application. By the way, the calculations may still return a negative value, if the user has changed the system’s date, but this is rather far-fetched.

You can implement write-only properties with the WriteOnly keyword. This type of property is implemented with a Set section only. But WriteOnly properties are of questionable value, and you’ll probably never use them.

Our Minimal class is no longer so minimal. It exposes some functionality, and you can easily add more. Add properties for name, profession, and income, and methods to calculate insurance rates and anything you can think of. Add a few members to the class, and check them out.

Before ending this section, let’s experiment a little with object variables. We’ll create two variables of the Minimal class and set some properties. Then, we’ll call the Equals method to compare them. Enter the lines of Listing 8.9 in a new button’s Click handler (this is the code behind the button named Test Equals Method on the test form).

Listing 8.9: Experimenting with Class Instances

Dim obj1 As New Minimal()

Obj1.property1 = “ABCDEFGHIJKLMNOPQRSTUVWXYZ” Dim obj2 As New Minimal()

obj2 = obj1

If obj1.Equals(obj2) Then Console.WriteLine(“They’re equal”) obj2.property1 = “abcdefghijklmnopqrstuvwxyz”

If obj1.Equals(obj2) Then Console.WriteLine(“They’re equal”)

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com