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