We have seen in our programs that sub-classes can call the methods defined in

Một phần của tài liệu introduction to vb.net manual (Trang 162 - 179)

Consider the following code

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 163 Imports System

Module Test

Public Sub Main()

' line 1 and line 2 will both do the same work 'Dim cal As new Callee() ' line 1

Dim cal As Caller = New Callee() ' line 2 cal.CallMethod()

End Sub End Module

MustInherit Class Caller Public Sub CallMethod()

Console.WriteLine("In CallMethod() of Caller class, about to call DoWork() defined in sub-class")

DoWork() End Sub

Public MustOverride Sub DoWork() End Class

Class Callee

Inherits Caller

Public Overrides Sub DoWork()

Console.WriteLine("DoWork() of class Callee called...") End Sub

End Class

Above, the CallMethod() method of the Caller class is calling the method DoWork() declared in the Caller class but defined in the Callee class. Hence, a method (CallMethod()) in the base-class (Caller) is calling a method (DoWork()) defined in its subclass (Callee).

What's Next…

Next time, we will be discussing exception handling mechanism in VB.Net. We will explore

• Exceptions basics

• Exceptions in .Net Framework

• Try…Catch...Finally blocks

• Throwing Exceptions

• Your Own Custom Exceptions

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 164 Exception Handling in VB.Net

Lesson Plan

Shortly we will explore the exception handling mechanism in VB.Net. We will start by

looking at the idea behind exceptions and how different exceptions are caught. Later we will explore the different features provided and the constraints applied by the VB.Net

programming language in exception handling. Finally we will learn how to define our own custom exceptions.

Exceptions Basics

Exception handling is a mechanism to manage run-time errors in .NET that would otherwise cause your software to terminate abruptly.

The need for Exceptions

Consider the following simple code Imports System

Module Test

Public Sub Main()

Dim p As Integer = ConvertToInteger("34") Console.WriteLine(p)

End Sub

Public Function ConvertToInteger(ByVal str As String) As Integer Dim i As Integer = Integer.Parse(str)

Return i End Function End Module

The ConvertToInteger() method returns the integer present in the string type. The output of this code will be

34

But what if the method ConvertToInteger() is called in the Main() method as Dim p As Integer = ConvertToInteger("My name")

There won't be a compile time error as the parameter 'My name' is in the required form of a string. However when the code is executed, the processor will attempt to convert the string 'My name' to an Integer which is offcourse not possible. The result, the program will crash!

What should we do now?

Exceptions in VB.Net and .Net Framework

People have worked on the problem of managing errors and have developed a solution in

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 165 the form of 'Exceptions'. Programmers may define and throw an

exception in the case of unexpected events. Below are some important points about exceptions and the exception handling mechanism in VB.Net and the .Net Framework:

• All exceptions in .Net are objects.

• The System.Exception class is the base class for all the exceptions in .Net

• Any method can raise or throw an exception in the case of some unexpected event during its execution using the throw keyword in VB.Net

• The thrown exception can be caught or dealt within the calling method using the Try...Catch block.

• The code that may throw an exception which we want to handle is put in the Try block. This is called an attempt to catch an exception.

• The code to handle the thrown exception is placed in the Catch block just after the Try block. This is called catching an exception. We can define which particular class of exception we want to deal in this Catch block by mentioning the name of the exception with the Catch keyword

• Multiple Catch blocks can be defined for a single Try block where each Catch block will Catch a particular class of exception.

• The code that must always be executed after the Try or Try...Catch block is placed in the Finally block. This is just after the Try or the Try...Catch block. This code is guaranteed to always be executed whether the exception occurs or not.

• When an exception is raised during the execution of code inside the Try block, the remaining code in the Try block is neglected and the control of execution is

transferred to the respective Catch or Finally block.

• Since exceptions are present in .Net as classes and objects they follow the

inheritance hierarchy. This means that if you write a Catch block to handle a base class exception, it will automatically handle all of its sub-class exceptions. Attempting to Catch any of the sub-class exceptions explicitly after the parent class exception will make render your code unreachable or useless.

• The Finally block is optional. Exception handling requires any combination of the Try...Catch or Try...Catch...Finally or Try...Finally blocks.

• If you do not Catch an exception the runtime environment (Common Language Runtime or CLR) will Catch it on your behalf and may cause your program to be terminated.

Author's Note: For VB6 developers, Try...Catch is .Net's replacement for On Error and is much more structured as you will see in this lesson. For Java developers, there is no concept of checked exceptions in VB.Net. All the exceptions are implicitly unchecked. Hence there is no throws keyword present in VB.Net. The absence of checked exceptions in VB.Net is quite a hot topic of debate since the birth of .Net. I personally feel that the idea of checked exceptions is extremely good and it should have been implemented in VB.Net.

See the Microsoft web site regards the argument of Hejlsberg and other designers of C# and why they haven't included checked exceptions in .Net http://msdn.microsoft.com/chats/vstudio/vstudio_032103.asp

Handling Exceptions using the Try...Catch...Finally blocks

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 166 Use of the Try...Catch block

A simple demonstration for the use of Try...Catch block is given below Public Sub Main()

Dim s As String = Nothing Try

Console.WriteLine("In Try block... before calling s.ToLower()") Console.WriteLine(s.ToLower())

Console.WriteLine("In Try block... after calling s.ToLower()") Catch e As NullReferenceException

Console.WriteLine("In Catch block...")

Console.WriteLine("NullReferenceException Caught") End Try

Console.WriteLine("After Try...Catch block") End Sub

The string 's' in the Main() method is assigned a Nothing value. If we attempt to call the ToLower() method with this null reference in the Console.WriteLine() method, the CLR (Common Language Runtime) will raise the NullReferenceException. Since we have enclosed the call to the ToLower() method in a Try block, the Runtime will search for a Catch block which can Catch this exception and, if one is found, the execution will jump to this Catch block. The syntax of the Catch block is important to understand. After the Catch, a

reference ('e' in our case) of our target exception class is declared (NullReferenceException in our case). When the above program is executed, the outputs is

In Try block... before calling s.ToLower() In Catch block...

NullReferenceException Caught After Try...Catch block

Press any key to continue

Carefully look at the output of the program and compare it with the source code. The call to s.ToLower() raised the NullReferenceException. As a result the execution of the remaining part of the Try block is ignored and the program execution is transferred to the Catch block.

Remember that the NullReferenceException is raised when we attempt to access the

members of a class using a null reference (Nothing). Lets change the code above a little and assign an object to the reference 's'

Public Sub Main()

Dim s As String = "Faraz"

Try

Console.WriteLine("In Try block... before calling s.ToLower()") Console.WriteLine(s.ToLower())

Console.WriteLine("In Try block... after calling s.ToLower()") Catch e As NullReferenceException

Console.WriteLine("In Catch block...")

Console.WriteLine("NullReferenceException Caught") End Try

Console.WriteLine("After Try...Catch block") End Sub

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 167 Since this code does not cause any exceptions to be raised, the execution of program will output as

In Try block... before calling s.ToLower() faraz

In Try block... after calling s.ToLower() After Try...Catch block

Press any key to continue

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 168 Exception class' Message and StackTrace Property

Note that the code under the Catch block didn't get executed because of the absence of an NullReferenceException. Now lets remove the Try...Catch block and see what happens Public Sub Main()

Dim s As String = Nothing

Console.WriteLine("Before printing lower case string...") Console.WriteLine(s.ToLower())

Console.WriteLine("After printing lower case string...") End Sub

When we compile and execute the above code, we see the following output Before printing lower case string...

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.

at VBDotNetSchoolLesson9.Test.Main() in C:\Documents and Settings\Administrat or\My Documents\Visual Studio Projects\VBDotNetSchoolLesson4\Module1.vb:line 7 Press any key to continue

Since we did not Catch the NullReferenceException, our program got terminated

prematurely with the runtime (CLR) reporting two things 1. An Exception Message: which describes the exception

2. A Stack Trace of the cause of execution: This is the hierarchy of function calls which caused the exception. In our case it shows that the exception is caused by the Main() method in the Test module which is contained in the VBDotNetSchoolLesson9 namespace (VBDotNetSchoolLesson9.Test.Main()). The Stack trace also points out the file name along with its complete path and the line number which contained the cause of the exception.

Because we don't want our program to crash when an exception occurs, we attempt to catch all the exceptions that can be caused by our code. Let's move to our previous code segment where we caught the NullReferenceException in the Catch block. We can also print the Message and Stack Trace of the exception using the Message and the StackTrace

properties of the Exception class. Examine the following code Public Sub Main()

Dim s As String = Nothing Try

Console.WriteLine("In Try block... before calling s.ToLower()") Console.WriteLine(s.ToLower())

Console.WriteLine("In Try block... after calling s.ToLower()") Catch e As NullReferenceException

Console.WriteLine(vbCrLf & "In Catch block...") Console.WriteLine("NullReferenceException Caught") Console.WriteLine(vbCrLf & "Exception Message") Console.WriteLine("=================" & vbCrLf) Console.WriteLine(e.Message)

Console.WriteLine(vbCrLf & "Exception Stack Trace") Console.WriteLine("=====================" & vbCrLf) Console.WriteLine(e.StackTrace)

End Try

Console.WriteLine(vbCrLf & "After Try...Catch block")

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 169 End Sub

The difference between the above and the previous code segment is that here we have printed the explanatory message and stack trace of the exception explicitly by use of the exception reference. The output of the program will be

In Try block... before calling s.ToLower() In Catch block...

NullReferenceException Caught Exception Message

=================

Object reference not set to an instance of an object.

Exception Stack Trace

=====================

at VBDotNetSchoolLesson9.Test.Main() in C:\Documents and Settings\Administrat or\My Documents\Visual Studio Projects\VBDotNetSchoolLesson4\Module1.vb:line 9 After Try...Catch block

Press any key to continue The Finally block

The optional Finally block comes just after the Try or Catch block. The code in the Finally block is guaranteed to always be executed whether an exception occurs or not in the Try block. Usually the Finally block is used to free any resources acquired within the Try block and hence could not be closed because of the exception. For example the Finally block can be used to close a file, database, socket connection or other important resources opened in the Try block. Let's add the Finally block to our previous code example.

Public Sub Main()

Dim s As String = "Faraz"

Try

Console.WriteLine("In Try block... before calling s.ToLower()") Console.WriteLine(s.ToLower())

Console.WriteLine("In Try block... after calling s.ToLower()") Catch e As NullReferenceException

Console.WriteLine(vbCrLf & "In Catch block...") Console.WriteLine("NullReferenceException Caught") Finally

Console.WriteLine(vbCrLf & "In Finally block...") End Try

End Sub

When we execute the program we see the following output In Try block... before calling s.ToLower()

Faraz

In Try block... after calling s.ToLower()

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 170 In Finally block...

Press any key to continue

Since no exception is raised, the code in the Finally block is executed just after the code in the Try block. Let's cause an exception to occur by setting the string 's' to Nothing in the Main() method

Public Sub Main()

Dim s As String = Nothing ...

End Sub

Now the output will be

In Try block... before calling s.ToLower() In Catch block...

NullReferenceException Caught In Finally block...

Press any key to continue

The output shows that the code in the Finally block is always executed after the execution of the Try and Catch block. This is regardless if an exception occurred or not.

It is possible to write the Try...Finally block without using a Catch block Public Sub Main()

Dim s As String = "Faraz"

Try

Console.WriteLine("In Try block... before calling s.ToLower()") Console.WriteLine(s.ToLower())

Console.WriteLine("In Try block... after calling s.ToLower()") Finally

Console.WriteLine(vbCrLf & "In Finally block...") End Try

End Sub

The output of the program is

In Try block... before calling s.ToLower() Faraz

In Try block... after calling s.ToLower() In Finally block...

Press any key to continue

The output of the program shows that the Finally block is always executed after the Try block.

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 171

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 172 Catching Multiple Exceptions using multiple Catch blocks

It is possible to catch multiple (different) exceptions that may be raised in a Try block using multiple (or a series of) catch blocks. For example we can write three Catch blocks; one for catching a NullReferenceException, the second for catching an IndexOutOfRangeException and the third is for any other exception (Exception). Remember that the

IndexOutOfRangeException is raised when an element of an array whose index is out of the range of the array is accessed. An out of range index can be either less than zero or greater than or equal to the size of the array. The code below demonstrates the use of multiple Catch blocks

Public Sub Main()

Dim s As String = "Faraz"

Dim i(2) As Integer Try

Console.WriteLine("Entering the Try block..." & vbCrLf) ' can cause NullReferenceException

Console.WriteLine("Lower case name is: " + s.ToLower())

' can cause NullReferenceException or IndexOutOfRangeException Console.WriteLine("First element of array is: " + i(0).ToString()) ' can cause DivideByZeroException

i(0) = 3

i(1) = CType(4 / i(0), Integer)

Console.WriteLine(vbCrLf & "Leaving the Try block...") Catch e As NullReferenceException

Console.WriteLine(vbCrLf & "In Catch block...") Console.WriteLine("NullReferenceException Caught") Catch e As IndexOutOfRangeException

Console.WriteLine(vbCrLf & "In Catch block...") Console.WriteLine("IndexOutOfRangeException Caught") Catch e As Exception

Console.WriteLine(vbCrLf & "In Catch block...") Console.WriteLine("Exception Caught")

Console.WriteLine(e.Message) End Try

End Sub

Here we have used the string 's' and an integer array 'i'. The size of the Integer array is declared as 3. There are three places in the program where we will introduce the occurrence of the exceptions.

• First 's' and 'i' can be Nothing or Null causing the NullReferenceException.

• Secondly, the access to the array 'i' may cause an IndexOutOfRangeException

• Finally the division of 4 by i(0) may cause an DivideByZeroException if the value of i(0) is zero.

We have declared three Catch blocks in the code for each of these types of exception. Note that the last Catch block is designed to catch any other exception except

NullReferenceException and IndexOutOfRangeException which have already been caught above. Only one of these exceptions can be raised, which will terminate the execution of the Try block and will transfer the execution to the respective Catch block.

When the above code is executed we will see the following output

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 173 Entering the Try block...

Lower case name is: Faraz First element of array is: 0 Leaving the Try block...

Press any key to continue

So far so good, no exception occurred. Let's first make the string reference 's' pointing to Nothing and see the effect

Public Sub Main()

Dim s As String = Nothing ...

End Sub

The output will be Entering the Try block...

In Catch block...

NullReferenceException Caught Press any key to continue

It looks similar and very much as expected. Now change the array index to an out of

bounds value (either less than zero or greater than or equal to 3). Also change the string 's' to point to another string to avoid the NullReferenceException

Console.WriteLine("Sixth element of array is: " + i(5).ToString()) …

The output will expectedly be Entering the Try block...

Lower case name is: Faraz In Catch block...

IndexOutOfRangeException Caught Press any key to continue

Finally correct the access to the array using a valid index and make the value of i(0) equal to zero to cause the DivideByZeroException

...

i(0) = 0 ...

Copyright © 2008 Department of Education - Introduction to Visual Basic – VB.Net Page 174 The output of the program will be

Entering the Try block...

Lower case name is: Faraz First element of array is: 0 In Catch block...

Exception Caught

Attempted to divide by zero.

Press any key to continue

The execution of 3/i(0) will cause the DivideByZeroException. The runtime checked for the presence of the Catch block. It found in the third Catch block the Exception which is the super type of DivideByZeroException (and any other exception in .Net). The execution is then transferred to the corresponding Catch block.

An important point to remember when using multiple Catch blocks

Since exceptions are present in .Net as classes and objects, they follow the inheritance hierarchy. This means that if you write a Catch block to handle a base class exception, it will automatically handle all of its sub-class exceptions. Attempting to catch any of the sub-class exceptions explicitly after the parent class exception, will cause this code to become

unreachable, dead, useless code. For example, review the following code Public Sub Main()

Dim s As String = Nothing Try

Console.WriteLine("Entering the Try block..." & vbCrLf) ' can cause NullReferenceException

Console.WriteLine("Lower case name is: " + s.ToLower()) Console.WriteLine(vbCrLf & "Leaving the Try block...") Catch e As Exception

Console.WriteLine(vbCrLf & "In Catch block...") Console.WriteLine("Exception Caught")

Console.WriteLine(e.Message) Catch e As NullReferenceException ''''''' Unreacable code

Console.WriteLine(vbCrLf & "In Catch block...") Console.WriteLine("NullReferenceException Caught") End Try

End Sub

Above, the Catch block, which is to handle the Exception type exception is placed prior to its sub-class exception (NullReferenceException). No matter what exception is raised in the Try block, it will always be caught by the first Catch block, making the second Catch block "a dead piece of code". Hence, one must consider the inheritance hierarchy of different exceptions while using multiple Catch blocks.

Author's Note: Unfortunately the VB.Net compiler does not detect the

unreachable or dead code and does not even produce a warning. While defining unreachable code concludes a compile time error in C#.

Other important points about Exception Handling in VB.Net

Một phần của tài liệu introduction to vb.net manual (Trang 162 - 179)

Tải bản đầy đủ (PDF)

(327 trang)