Page 1 of 1

Error handling for beginners - Part two "Try - Catch" Handling errors with "Try - Catch" - a beginners guide. Rate Topic: ***** 1 Votes

#1 jens  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 67
  • View blog
  • Posts: 430
  • Joined: 09-May 08

Post icon  Posted 19 February 2009 - 03:30 PM

VB.NET: Error handling for beginners - Part two, handling run time errors with "Try - Catch".

A tutorial for the beginner on error handling in VB.NET. This - part two - is about basic structured error handling with "Try - Catch" pertaining to run time errors. More info on this can be found by highlighting "Try" and pressing <F1> in the IDE.

1) Basics of error handling.
1.1) Simplest possible - catch all.
1.2) Catching specific errors
1.3) Error propagation
1.4) Execution paths and the lifetime of an error
1.5) Priority rules of error catching
1.6) Nested error handling
1.7) Finally...
1.8) Conclusion and a not so bright idea


Having written this second tutorial I find it kind of bloated. I'm sorry about this, the thing is that I don't know how to make it shorter and still explain all these things about error handling.

Anyway, you might wonder why such a simple thing as error handling needs such an in depth tutorial - even on this basic level. This is because I want to explain as much as possible since I think error handling is really important.

Why so? Well, you do your best to foresee any problems but there are always ingenious errors introduced by users or by the complexity of a solution that you keep building on. Good error handling can save your application in many cases and might save the user from loosing data and/or difficult decisions. A friendly "Well, things didn't work out so well but the program has saved as much as possible of your work in your default directory. Check your configuration and restart." is always better than "Error writing file. Continue or end?". Try to take care of stuff as far as possible and when your program dies, try to die gracefully. :)

Once you figure out how this works it's pretty straight forward, however there are a lot of special cases one needs to explore.


1) Basics of error handling.

So then, you have your program compiled with option strict on and option explicit on. You have checked that the output is correct within defined limits of your goal. And now you want to take care of those ugly run time errors? (If this doesn't make sense to you please check part one of this tutorial).


1.1) Simplest possible - catch all.

In the first tutorial we had this overflow error that we handled nicely enough.
Build and run the following code. (By this I mean that you do Build -> Build in the IDE and then run the exe.)
Option Explicit On
Option Strict On

Public Class Form1

	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		Dim counter As Integer, sum As Integer

		sum = 0
		Try
			For counter = 1 To 1000000
				sum += counter
			Next
		Catch ex1 As exception
			MsgBox("There's an error: " & vbCrLf & ex1.ToString)
		End Try
	End Sub

End Class



What happens here is that while executing between the Try and the Catch there is a special lookout checking for exceptions (errors). Whenever one is present execution jumps to the part between Catch and End Try. Without the error handling the error would be thrown in the face of the user - who presumably isn't happy about it.

You could, and probably should, have more code to handle the errors where the message box is. This code just shows - as an example - where to put code for dealing with the problem.

Checking for exceptions and dealing with them costs a lot in performance compared to checking input and other circumstances. Because of this I strongly suggest that you do not - repeat not - use error handling as a substitute for checking data before you try to use it. One more reason not to use error handling instead of checking data is that it inevitably leads to sloppy coding.

One thing introduced here is the possibility to use the error in your error handling code. As you see I use the ex1.ToString to get more information on the error. Going in to this any further is beyond this tutorial - you're on your own. :)

The code above is a bit dull, let's make things a bit more interesting.


1.2) Catching specific errors

A Short can only hold a little more than 32000. The following program will overflow on the row test *= test and throw an OverflowException. This can be caught in different ways, check it out.

Build and run the following.
Option Explicit On
Option Strict On

Public Class Form1

	Private Sub HandledError1()
		Dim test As Short

		Try
			test = 16000
			test *= test
			'Catch ex1 As IndexOutOfRangeException
			'Catch ex1 As OverflowException
		Catch ex1 As Exception
			MsgBox("We caught an exception in the sub: " & ex1.ToString)
		End Try
	End Sub

	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		HandledError1()
	End Sub

End Class



The Catch ex1 As Exception will catch any error, the other two will catch only their specified errors. Try commenting out one "Catch" row at a time then build and run, notice what happens.

Since we are generating an overflow exception the row Catch ex1 As IndexOutOfRangeException will not catch our error and it will be thrown at the user, the Catch ex1 As OverflowException however will catch it. We have here a way of deciding what errors to take care of! Lets take this a little further.

One reason to use procedures (subs or functions) is that we want to use the same code in different places in our programs, we do this by calling procedures from these places. Handling the error in the procedure might not always be the best way of dealing with the problem. Could we do it some other way?


1.3) Error propagation

Lets try to take care of the problem in the calling code...
Option Explicit On
Option Strict On

Public Class Form1

	Private Sub HandledError1()
		Dim test As Short

		Try
			test = 16000
			test *= test
		Catch ex1 As IndexOutOfRangeException
			MsgBox("We caught an Index out of range exception in the sub: " & ex1.ToString)
			'Catch ex2 As OverflowException
			'MsgBox("We caught an overflow exception in the sub: " & ex2.ToString)
		End Try
	End Sub

	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		Try
			HandledError1()
		Catch ex1 As Exception
			MsgBox("Caught an unspecified error in the calling code: " & vbCrLf & ex1.ToString)
		End Try
	End Sub

End Class



This time, build and run the program then un comment the two commented rows, build and run and notice what happens.

First - it's kind of remarkable that errors that aren't handled where they happen might be taken care of at a higher level - by the calling code! This is called Error propagation - errors that are not taken care of "floats" (they are propagated) up through code levels until something (or someone) takes care of them. Ultimately the highest level is a poor user who will have to deal with the error, unless it's taken care of somewhere on the way.

Second - we now have a way to decide what errors should be taken care of where! But! You must take care of specific errors first and less specific errors later - further up the propagation hierarchy.


1.4) Execution paths and the lifetime of an error

Try this
Option Explicit On
Option Strict On

Public Class Form1

	Private Sub HandledError1()
		Dim test As Short

		Try
			test = 16000
			test *= test
		Catch ex1 As IndexOutOfRangeException
			MsgBox("We caught an Index out of range exception in the sub: " & ex1.ToString)
			'Catch ex2 As Exception
			'MsgBox("Caught an unspecified error in the sub: " & vbCrLf & ex2.ToString)
			'Exit Sub
		End Try
		MsgBox("Just to know we are here")
	End Sub

	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		Try
			HandledError1()
		Catch ex2 As OverflowException
			MsgBox("We caught an overflow exception in the calling code: " & ex2.ToString)
		End Try
	End Sub

End Class



Build and run the code then un comment the lines Catch ex2 As Exception and MsgBox("Caught an unspecified error in the sub: " & vbCrLf & ex2.ToString) , build and run again, finally un comment the line Exit Sub, build and run.

There are three things to notice here:
First - when there is an error that is not taken care of execution stops and jumps to a higher level. When the commenting out is in place you never get the "Just to know we are here" message box.
Second - when you do take care of the error at a certain level the code keeps on executing after the Try - Catch block. This behavior can be changed by putting a Exit Sub statement in the Try - Catch block.
Third - when an error is taken care of it is "used up" and code higher up won't know anything about it.

In the above code I use Exit Sub to jump out of the sub routine after the error has been handled. There is also a Exit Try statement that might come in handy. When encountered, either in the Try part or in the Catch part, it will make execution to jump out of the Try - Catch and start executing the first line of code directly after the Try - Catch. I really don't know when I'd use it but it's there in case you need it. :)

Great! Now we can take care of the error in different ways depending on the context. Suppose you're trying to open a file. In one case it's some function of yours that wants to open and read a file, in another case it's the user requesting a file. Those would need to be handled differently and it can be solved by putting different error handling code in the Try - Catch block surrounding each call to the procedure that opens the file.

This might raise some concern about where to put error handling code, close to the error (in this case in the sub) or at a higher level (in this case in the calling code)? Well, that requires some thinking. If - I say if - there is a straight answer I'd say that you put error handling code where the knowledge is. What knowledge you might ask - the knowledge of how to deal with the problem. Put the error handling code where you can take care of the error in some intelligent way. File read errors might be handled a bit up in the code calling hierarchy, at least if both humans and programs are using it. Other errors e.g. such as being unable to connect to a database might be taken care of in the sub - close to the data base work.


1.5) Priority rules of error catching

Just to show how this works - build and run...
Option Explicit On
Option Strict On

Public Class Form1

	Private Sub HandledError1()
		Dim test As Short

		Try
			test = 16000
			test *= test
			'Catch ex0 As Exception
			'MsgBox("Caught an unspecified error 1 in the sub: " & vbCrLf & ex0.ToString)
		Catch ex1 As OverflowException
			MsgBox("We caught an Index out of range exception in the sub: " & vbCrLf & ex1.ToString)
		Catch ex2 As Exception
			MsgBox("Caught an unspecified error 2 in the sub: " & vbCrLf & ex2.ToString)
		End Try
		MsgBox("Just to know we are here")
	End Sub

	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		HandledError1()
	End Sub

End Class



Now un comment, build and run again - ignoring the squiggly lines. You'll see that catching an unspecific error in a Try - Catch with several catches inhibits more specific error handling. This shows there are rules of priority, the order of your catch statements is important.

If you haven't noticed it before, now observe that I'm catching the errors using different names, e.g. ex1 and ex2. This isn't strictly necessary here but further on it will come in handy.


1.6) Nested error handling

You might find yourself in situations where taking care of one error results in a new error.

You need a text box and a button on your form; build and run the following code.
Option Explicit On
Option Strict On

Public Class Form1

	Private Sub HandledError1(ByVal upLimit As Integer)
		Dim test As Short
		Dim ourArray(3) As Integer

		Try
			test = 16000
			test *= test
		Catch ex1 As OverflowException
			MsgBox("We caught an OverflowException in the sub.")
			Try
				For i As Integer = 0 To upLimit
					ourArray(i) = i
				Next i
			Catch ex2 As IndexOutOfRangeException
				MsgBox("We caught an index out of range exception in the subs error handling")
			End Try
			MsgBox("Sub after catch two")
		End Try
		MsgBox("Sub after catch one")
	End Sub

	Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
		Dim forLimit As Integer

		Try
			If isnumeric(textbox1.text.trim) Then 'Checking user input - could be improved.
				forLimit = CInt(TextBox1.Text.Trim)
				HandledError1(forLimit)
			Else
				MsgBox("Please provide a number")
			End If
		Catch ex1 As Exception
			MsgBox("We caught an exception from the sub in the calling code.")
		End Try
	End Sub
End Class



Run the above and put a number < 4 in the text box before clicking the button, then try with a number >= 4. Notice how a number >= 4 gives an error in the error handling code of the first error.

Now this example is really stupid but the method is useful. Lets say you are saving stuff like user data and configuration data to two different files. Writing the second file fails which makes you want to delete the first file. In this case you might want to have a delete statement in the error handling for writing the second file, that delete statement should be wrapped in its own Try - Catch in case anything goes wrong.


1.7) Finally

So, we have taken care of our errors. We have learned to keep the program running after an error or jumping out of the sub or error handling code in case of an error. There's also a way to make sure that a certain piece of code is executed whether or not the Try - Catch encounters an error. Say hello to "Finally"!

Build and run...
Option Explicit On
Option Strict On

Public Class Form1

	Private Sub HandledError1()
		Dim test As Short

		Try
			test = 16000
			'test *= test
		Catch ex1 As Exception
			MsgBox("We caught an exception in the sub: " & vbCrLf & ex1.ToString)
			Exit Sub
		Finally
			MsgBox("We are in finally.")
		End Try
		MsgBox("We are after the Try.")
	End Sub

	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		HandledError1()
	End Sub

End Class



Build and run the code, then un comment the line 'test *= test, build and run again.

Now this is a method that is very handy. Let say you have a data base connection open. If there's no error you want to close the connection and continue running the sub, i.e. showing the MsgBox("We are after the Try."). However if there is an error you want to close the connection and then jump out of the sub. This can be achieved by ugly coding - or by using finally.

The "Finally" will always be run, without regard to the presence of an error and without regard of any instructions to jump out of the Try - Catch or the sub. Of course this can be misused too - I think it's possible to cause confusion by using a combination of Exit and Finally in a really large piece of error handling code. But then the code would probably be kind of messy anyway.


1.8) Conclusion and a not so bright idea

What have we learned?
* Errors that are not handled immediately will propagate up through the code until something takes care of them.
* Error handling can deal with specific errors or unspecified errors. If we want to combine these we have to deal with the specific errors first.
* You can have multiple Catch-statements in a Try - Catch block in order to deal with different kinds of errors in different ways.
* By ignoring (all but certain) errors, those ignored will be propagated to a higher code level.
* Once an error have been dealt with it is "used up" and can't be handled at another place.
* Error statements can be nested. This can come in handy but don't overdo it. :)
* Error handling code can force execution to jump out of a Try - Catch or out of the sub where it's running.
* Finally - make sure a piece of code is executed whether or not there's an error and/or exit.
* There's a wealth on error handling by highlighting "Try" and pressing <F1> in the IDE. :)

A not so bright idea...

I can see one or two of you guys getting a really bright idea about now: Why not put one big "Try - Catch" around all the outermost code and not bother in other places... Since any error propagates to the outermost calling code we could let it handle everything and be done with all this. :) Lets just wrap everything in our main method (or other starting point) in a "Try - Catch" and we'll newer throw a un handled exception at our users again!

NO! No, no, no! That's NOT how you're supposed to take advantage of error propagation, not ever. Do NOT do that. You have been warned! Only if you have been a good boy (or girl) and taken care of every error you can think of after securing your code from invalid input and strange circumstances you may put a "Try - Catch" around the code in your main - as a very last resort and then mainly to die gracefully. ;)


This concludes part two of my error handling tutorial. While working on it I found some more interesting things to do with errors. I'll put them in a part three.

Regards
/Jens


PS: Please comment if you like the tutorials approach to the subject. Please criticize the presentation. I very much want to write clear and easy to follow tutorials - help me! :)

This post has been edited by jens: 23 February 2009 - 05:50 AM


Is This A Good Question/Topic? 0
  • +

Replies To: Error handling for beginners - Part two "Try - Catch"

#2 wtfnix  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 7
  • Joined: 08-April 09

Posted 08 April 2009 - 03:06 PM

Quote

Having written this second tutorial I find it kind of bloated.


Never too bloated, I have printed this whole series of Error Handling out, because this is VERY invaluable information to not only a beginner, but to an advanced vb.net coder as I see it. Thanks for such great writings.
Was This Post Helpful? 0
  • +
  • -

#3 sujatak  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 06-February 10

Posted 06 February 2010 - 02:26 PM

can you give me link for part1,3,4 etc
Was This Post Helpful? 0
  • +
  • -

#4 jens  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 67
  • View blog
  • Posts: 430
  • Joined: 09-May 08

Posted 22 March 2010 - 11:59 AM

I'm sorry Sujatak, I don't understand what links it is you want. /Jens
Was This Post Helpful? 0
  • +
  • -

#5 JoshD  Icon User is offline

  • D.I.C Head

Reputation: 9
  • View blog
  • Posts: 111
  • Joined: 22-March 10

Posted 12 April 2010 - 03:41 PM

View Postjens, on 19 February 2009 - 02:30 PM, said:

VB.NET: Error handling for beginners - Part two, handling run time errors with "Try - Catch".

you said this is part two.
sujatak would like a link to part one, and any parts following part two.
Was This Post Helpful? 0
  • +
  • -

#6 jens  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 67
  • View blog
  • Posts: 430
  • Joined: 09-May 08

Posted 27 August 2010 - 06:08 AM

Sorry to be so late to reply...
Error handling for beginners part one.
Error handling for beginners part two.
Error handling part three.
Was This Post Helpful? 0
  • +
  • -

#7 Joey1970  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 01-June 13

Posted 01 June 2013 - 07:35 PM

Problem I am having is where you added the lines
Catch ex1 As OverflowException
Catch ex2 As IndexOutOfRangeException

AS I write code, How do i know what exceptions my code needs in include without having ran my code and tested for bunk conditions, trapped it with break points and then checking to see which exception is being called?

View PostJoey1970, on 01 June 2013 - 07:31 PM, said:

Problem I am having is where you added the lines
Catch ex1 As OverflowException
Catch ex2 As IndexOutOfRangeException

AS I write code, How do i know what exceptions my code needs to include without having ran my code and tested for bunk conditions, trapped it with break points and then checking to see which exception is being called?

Was This Post Helpful? 0
  • +
  • -

#8 alapee  Icon User is online

  • The North American Snipe

Reputation: 94
  • View blog
  • Posts: 1,610
  • Joined: 24-October 13

Posted 25 October 2013 - 09:26 AM

Ok, I am guilty of using On Error Goto ErrorText, so I thought I would look into more practical ways of error handling (since it is one of my weak points). This might be a dumb question, but where do the disposal statements go? I am currently thinking the "Finally" Block. Also how do you handle code breaks for instance if I have statement:
if fso.filexists(strFileLocation)= true then



Normally I would Do this (but I am trying to code better)
public sub Example()
On error goto ErrorText
dim fso as new filesystemobject
dim strFilelocation as string = "C:\File_Location\file.doc"
if fso.fileexists(strFileLocation) = true then
goto Exithere
end if
'Do Some Code
ExitHere:
fso = nothing
strfilelocation =vbempty
exit Sub 
ErrorText:
Msgbox (err.number & vbcrlf & err.description)
goto exithere
end sub


So how would the fso statement fit in?
I am sorry if it is a dumb question, I am just trying to wrap my brain around it.
Was This Post Helpful? 0
  • +
  • -

#9 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8911
  • View blog
  • Posts: 33,424
  • Joined: 12-June 08

Posted 25 October 2013 - 09:33 AM

Disposals would typically go in the 'finally' statement.


 Public Sub Example()
        Dim fso As filesystemobject
        Dim strFilelocation As String = String.Empty

        Try
            fso = New filesystemobject
            strFilelocation = "C:\File_Location\file.doc"
            If fso.fileexists(strFilelocation) Then
                Exit Sub
                'Else '-- typically I would have an else here
            End If
        Catch ex As Exception
            MsgBox(Err.Number & vbCrLf & Err.Description)
        Finally
            fso = Nothing
            strFilelocation = String.Empty
        End Try
    End Sub

Was This Post Helpful? 1
  • +
  • -

#10 alapee  Icon User is online

  • The North American Snipe

Reputation: 94
  • View blog
  • Posts: 1,610
  • Joined: 24-October 13

Posted 25 October 2013 - 09:57 AM

View Postmodi123_1, on 25 October 2013 - 11:33 AM, said:

Disposals would typically go in the 'finally' statement.


 Public Sub Example()
        Dim fso As filesystemobject
        Dim strFilelocation As String = String.Empty

        Try
            fso = New filesystemobject
            strFilelocation = "C:\File_Location\file.doc"
            If fso.fileexists(strFilelocation) Then
                Exit Sub
                'Else '-- typically I would have an else here
            End If
        Catch ex As Exception
            MsgBox(Err.Number & vbCrLf & Err.Description)
        Finally
            fso = Nothing
            strFilelocation = String.Empty
        End Try
    End Sub

Thank for getting back with me. This was very informative. Now onto research the using statement with a reassignment for the main object.

Curiosity question why an else? If the file exists at the location and you are exiting , logic dictates that if it doesn't you are not exiting therefore it moves down to the rest of the code.
So why use an else statement?

Thanks again for clarifying it for me.
Was This Post Helpful? 0
  • +
  • -

#11 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8911
  • View blog
  • Posts: 33,424
  • Joined: 12-June 08

Posted 25 October 2013 - 11:26 AM

Quote

Curiosity question why an else? If the file exists at the location and you are exiting , logic dictates that if it doesn't you are not exiting therefore it moves down to the rest of the code.
So why use an else statement?

I guess I was just looking at it in context of the method.. That is to say I wouldn't have a method dedicated to just checking if a file exists.. it would just be part of a larger function.. (and I would use System.IO.File.Exists(<file path string>) ).. Reading it (as a whole) just seems to ask for it to do something else besides checking it's existence.
Was This Post Helpful? 0
  • +
  • -

#12 alapee  Icon User is online

  • The North American Snipe

Reputation: 94
  • View blog
  • Posts: 1,610
  • Joined: 24-October 13

Posted 25 October 2013 - 11:58 AM

View Postmodi123_1, on 25 October 2013 - 01:26 PM, said:

Quote

Curiosity question why an else? If the file exists at the location and you are exiting , logic dictates that if it doesn't you are not exiting therefore it moves down to the rest of the code.
So why use an else statement?

I guess I was just looking at it in context of the method.. That is to say I wouldn't have a method dedicated to just checking if a file exists.. it would just be part of a larger function.. (and I would use System.IO.File.Exists(<file path string>) ).. Reading it (as a whole) just seems to ask for it to do something else besides checking it's existence.

The example is unclear now looking at it. I just thought it was something I was missing. If we got right down too (now looking at it and after much research since then) the coding would be more simplified.
Public Sub Example()
        Dim fso As FileSystemObject = New FileSystemObject
        Dim strFileLocation As String = "C:\File_Location\file.txt"
        Try
            If fso.fileexists(strFilelocation) = false  Then
                fso.CreateTextFile(strFileLocation)
            End If
            'Do Some More Code
        Catch ex As Exception
            MsgBox("Error: " & vbCrLf & Err.Number & vbCrLf & Err.Description &  vbCrLf & Err.HelpFile)
        Finally
            fso = Nothing
            strFilelocation = String.Empty
        End Try
    End Sub


If I finally got the concept down. I use the FSO because most of the time I am in VBA. I will have to check on the
System.IO.File.Exists Method (?) since now I am in an Actual VB.net Project.
Thanks again for the clarity on it, After Researching about the amazing using statement and further information on IDisposable Class (?). I realized a couple more coding practices I need to put into place. As you can see from above I have already started honing those skills.

This post has been edited by alapee: 25 October 2013 - 12:04 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1