Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Visual Basic 2005 Express Edition - From Novice To Professional (2006)

.pdf
Скачиваний:
386
Добавлен:
17.08.2013
Размер:
21.25 Mб
Скачать

150

C H A P T E R 5 M O R E - A D V A N C E D O B J E C T O R I E N T A T I O N

Casting Types

When you start to work with inheritance, abstract classes, and interfaces, the ability to treat one object as another becomes more and more important. In fact, even if you don’t use inheritance and interfaces in your projects (you should, really), you’ll still need to know how to cast one type of object as another. The reason for this of course is that the

.NET class library makes extensive use of inheritance, abstract classes, and interfaces. There are a couple of rules about just what you can cast objects into. Simply put, you

can only cast an object down to something it inherited from, or back to the original type of object that was created. This is probably easier to illustrate with a diagram (see Figure 5-11).

Object

Person

Employee

Team Leader

Manager

Director

Figure 5-11. A simple inheritance tree

In this example, if you went ahead and created a Director object, you could cast it down into pretty much any of the objects it inherited from. In VB you can inherit from only a single object (although you can implement multiple interfaces), so it’s quite painless to build nice easy-to-follow inheritance trees like this one.

So, a Director object could easily be treated just like a standard Employee one with code like this:

Dim myEmployee as Employee = myDirector

C H A P T E R 5 M O R E - A D V A N C E D O B J E C T O R I E N T A T I O N

151

Visual Basic 2005 is pretty smart at automatically spotting that you can convert one object into its superclass (the one it inherited from). Sometimes, though, you’ll need to help it out, particularly when you need to convert a base object reference into the more specific subclass type. Let’s look at an example.

Try It Out: Casting and Type Evaluation

Start up a new console application and add a new class to it called Employee.vb. When the code editor for the new class appears, add some code, like this:

Public Class Employee

Public Sub Hire()

Console.WriteLine("I got hired")

End Sub

End Class

Public Class Director

Inherits Employee

Public Sub GetHiringBonus()

Console.WriteLine("I also got a bonus")

End Sub

End Class

So, here you have an Employee class with a single method, and a Director class that inherits from it, adding the GetHiringBonus() method to the mix. Drop back into the Module1.vb code and type the bolded code in and I’ll talk you through it when you’re finished:

Module Module1

Sub Main()

Ind: delDim newHire As Employee = New Director() newHire.Hire()

If TypeOf newHire Is Director Then

CType(newHire, Director).GetHiringBonus()

End If

Console.ReadLine()

End Sub

End Module

152

C H A P T E R 5 M O R E - A D V A N C E D O B J E C T O R I E N T A T I O N

The first thing the code does is create a new object, called newHire. The object type is Employee, but you store a new Director object inside. This works, because Director subclasses Employee and can thus be treated the same in code.

The next line calls Hire(), the method you added to the Employee class. Even though this is really a Director object, the call works because on the one hand you’re treating the object like an Employee object, and on the other hand Director subclasses Employee and automatically gets its own Hire() method as a result.

Now, what if you needed to get back to the original Director object? Because you are working with an object variable declared as Employee, you can’t just call GetHiringBonus() on it. So, the next thing you need to do is see whether the object you are working with is really a Director. That’s where the TypeOf and Is keywords come into play:

If TypeOf newHire Is Director Then

All this does is see whether the “type of” your object is a Director.

If the object is really a Director (it is), you need to “cast” it back into the Director type. That’s what CType does. CType attempts to convert one object into another type:

CType(newHire, Director).GetHiringBonus()

You can either store the result of the call to CType into another variable, or just call methods on it. What it does here is attempt to convert your newHire object (an Employee) into a Director. It then calls

GetHiringBonus() on the resulting Director object.

Run the program now and you’ll see the output in Figure 5-12.

Figure 5-12. You can use CType to convert one object to another, and TypeOf to check whether one object is another.

You can also use CType to convert between the built-in Visual Basic types, for example converting a Double to an Integer.

C H A P T E R 5 M O R E - A D V A N C E D O B J E C T O R I E N T A T I O N

153

Reference Types and Value Types

All that brings us nicely on to reference types. Take a look at this code:

Sub Main()

Dim a As Integer = 2 Dim b As Integer = a * 2 b = b + 10

End Sub

Without keying it in, what do you think the values of a and b are at the end of this program? You’d be right if you said that a is 2 and b is 14. Integer is one of the simple data types that you looked at in Chapter 3. When you say something like a = b, the value inside b actually gets copied into a.

Now, look at this code:

Module Module1

Sub Main()

Dim myEmployee As New Employee() myEmployee.Name = "Pete"

Dim newEmployee As Employee newEmployee = myEmployee

newEmployee.Name = "Dominic" End Sub

End Module

Public Class Employee

Public Name As String

End Class

What do you think the values of myEmployee.Name and newEmployee.Name are at the end of Main()? Strangely, both are set to Dominic.

Objects are known as reference types, so setting objectA = objectB doesn’t copy objectB into objectA. Instead objectA is set to reference objectB. In some other languages this would be called a pointer. Assigning one object to another will only set both variables to reference the same object in memory.

At the end of the day, that’s all object variables do anyway. When you create an object, the .NET runtime creates it in the memory of your computer and then stores a reference to it inside your variable. So what really happens when you assign one object variable to another is that the reference is copied, but the object pointed to remains the same.

154

C H A P T E R 5 M O R E - A D V A N C E D O B J E C T O R I E N T A T I O N

It’s because of this that casting works. Because object variables don’t actually hold objects, it’s easy to tell Visual Basic exactly what type of object a variable points to. Of course, behind the scenes Visual Basic works some magic so that you don’t try to cast the impossible, but you don’t need to ever worry about that unless the compiler gives you an error.

This also brings us onto the ByVal keyword that you’ve seen Visual Basic adding to your methods, for example:

Sub SayHello(ByVal name As String)

End Sub

ByVal indicates that the actual value of any variable passed to this method is copied into the method’s name parameter. The alternative would be ByRef:

Sub SayHello(ByRef name As String)

End Sub

In this case, a pointer to the variable itself is passed into the subroutine. This means that if the subroutine changes its name in any way, then it will also be changed in the code that called the subroutine. I’m not going to dive into a full “Try It Out” here, but here’s some example code that you can key in yourself:

Module Module1

Sub Main()

Dim someValue As Integer = 12

SafeSubroutine(someValue)

Console.WriteLine("Some value is {0}", someValue)

UnsafeSubroutine(someValue)

Console.WriteLine("Some value is now {0}", someValue)

Console.ReadLine()

End Sub

C H A P T E R 5 M O R E - A D V A N C E D O B J E C T O R I E N T A T I O N

155

Public Sub SafeSubroutine(ByVal a As Integer)

a = a * 10

End Sub

Public Sub UnsafeSubroutine(ByRef a As Integer)

a = a + 50

End Sub

End Module

What this program does is create a variable (someValue) and then pass it to one routine ByRef, and another ByVal.

SafeSubroutine gets the value ByVal. So, it adds 10 only to its own local copy of the number.

UnSafeSubroutine, on the other hand, gets the value ByRef. So, when it adds 50 to the number, it’s actually adding 50 to our original variable. If you do key this in and run it, you’ll see the output in Figure 5-13.

Figure 5-13. By passing a value to a routine, ByRef actually passes a “reference” to the original variable over to the subroutine.

Obviously, using ByRef can introduce some very nasty side effects into your programs, so why on earth would you want to use it? Well, the answer is simple. When you are working with classes and objects of your own, you’ll often need to pass the object to a subroutine ByRef because there’s no easy way for Visual Basic to extract the “value” of a custom class you developed.

156

C H A P T E R 5 M O R E - A D V A N C E D O B J E C T O R I E N T A T I O N

BOXING AND UNBOXING

Since we’re talking about reference and value types, and casting, now would be a great time to mention a little behind-the-scenes “gotcha.” Every type in .NET derives from the base System.Object type, which effectively means that you can treat anything as System.Object. You need to be careful doing this, though, because of how .NET works with reference and value types differently.

Without going into a massive amount of detail, value types are stored on a small chunk of memory called the stack. Reference types, on the other hand, live on the heap, the larger “main” memory, if you like, in your PC. If you cast a value type to a reference type, it gets boxed. This means that .NET will allocate a lump of heap memory for a real object, and then move the value into that lump. If this happens a great deal in your program, you could notice performance problems because boxing takes time. Unboxing is the reverse. When you cast from a System.Object type to a value type, the wrappers get torn off the heap object, and the value is then moved to the stack, another costly maneuver if speed and performance is your primary goal.

Just something to be aware of.

Summary

We’ve covered a lot of ground in this chapter, focusing on the more advanced stuff that you are likely to want, or need, to do with objects. Object references, interfaces, and casting can take a little while to get used to if you are new to the world of Visual Basic 2005, but they are invaluable tools that will stand you in good stead.

The next chapter wraps up your introduction to the features of the Visual Basic 2005 language with a look at exceptions. With that out of the way, you’ll be ready to start learning all about what it takes to use Visual Basic 2005 Express to write great Windows applications.

C H A P T E R 6

■ ■ ■

Handling Exceptions

Occasionally programs go wrong. As users, we see these events as crashes. As programmers, we see them as exceptions, exceptional circumstances that cause the program to do something we really didn’t want it to do.

In the Microsoft .NET Framework, exceptions serve two purposes. On the one hand, they are the first stages of a nasty crash (if left unchecked) that will leave your users less than amused and potentially cause them to lose data, or at least faith in your program. On the other hand, exceptions are the mechanism that all of the .NET Framework class library uses to tell your code something has gone wrong. If your code chooses to ignore the exception, you get a crash. Smart programmers, though, know how to handle them and deal with them intelligently so that the users of your program don’t wander off to something more stable.

In this short chapter you’ll take a look at the world of exceptions. You’ll see how to make your own exceptions and learn just why that’s a useful skill to have. You’ll also see how to handle exceptions raised by either your code or .NET itself. I’ll also try to give you a little insight into what are the right and wrong ways to work with exceptions, and why exceptions are not always a good idea.

Understanding Exceptions

Like everything in .NET, an exception is an object. Specifically, an exception is an object that inherits functionality from System.Exception. The actual type of the exception is a good indicator as to roughly what went wrong, while the data contained inside the exception object can pinpoint exactly what happened, where, and why.

In less-technicalspeak, an exception is your program complaining. You ask some object to do something, and it finds that it can’t for whatever reason and complains loudly. It complains by creating an object based on System.Exception, filling in some fields telling you exactly why it can’t do something, and then stopping altogether.

Let’s take a look at a brief example.

157

158

C H A P T E R 6 H A N D L I N G E X C E P T I O N S

Try It Out: What Is an Exception?

Let’s write a simple Windows division application that’s bound to fail in spectacular fashion. Start up a new Windows Forms application and drop some controls onto the form as shown in Figure 6-1.

Figure 6-1. Arrange controls on your application’s form like this.

As always with Windows GUI examples, you’ll need to set up the names of the controls so that they are the same as mine so the example code works on your machine. The first text box should be named dividendBox, the second is divisorBox, and the third is resultBox. Set the name of the button control to divideButton.

Double-click the Divide button to start writing the code to respond to the button being clicked. Just go ahead and fill in the method as shown here:

Public Class Form1

Private Sub divideButton_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles divideButton.Click

Dim dividend As Double = Double.Parse(dividendBox.Text)

Dim divisor As Double = Double.Parse(divisorBox.Text)

resultBox.Text = (dividend / divisor).ToString()

End Sub

End Class

First, a Double variable is created to hold the dividend in the calculation. Double.Parse() is used to turn the text in the dividendBox into a Double value that you can work with. The same technique is used to get the divisor’s Double value.

C H A P T E R 6 H A N D L I N G E X C E P T I O N S

159

Finally, the resultBox’s text is set to the result of the dividend divided by the divisor. Notice that you’ve enclosed the calculation in parentheses. This enables you to treat the entire calculation just as if it were a Double value or variable, and call ToString() on it to turn the result into text.

Run the program and key in 12 in the first text box, 3 in the second, and click the Divide button. Everything runs great, and you’ll see the result of 4 displayed in the result box, just as in Figure 6-2.

Figure 6-2. Enter valid numbers into the first two text boxes, and the program will run just fine.

Now type 12 in the first text box and the word three in the second, and click the Divide button. The result is shown in Figure 6-3.

Figure 6-3. This is what exceptions look like when you run a program from within the IDE. To your users, they look much worse.

An exception occurs because Double.Parse() expects to be given a string containing numeric data, but you gave it straight text. When an exception occurs while running a program from the Visual Basic 2005 Express IDE, the program will stop and the line of code that failed will be highlighted, just as you can see. In addition, a dialog box appears, explaining what the exception was, in this case “FormatException was unhandled,” along with some options for things that you can do. Click the link in that box that says View Detail. This takes you to a detailed view of the exception, shown in Figure 6-4.