Try Catch Else Finally

  • Thread starter Thread starter cj
  • Start date Start date
Hi Cj
1. is the button1_click catch catching exceptions thrown by lines inside
dofilestuff or just if the line dofilestuff itself for some reason threw
an exception?

The Catch in Button1_Click() catches any exception that 'escapes' from
DoFileStuff(). So, if UnexpectedException is thrown it will be caught in
Button1_Click(). If SomeException is thrown it will be caught in
DoFileStuff(). If DoFileStuff() rethrows it, or throws it as some other
exception, then that will be caught in Button1_Click(). Otherwise,
DoFileStuff() can consume the exception and retry the offending code or move
on to the next iteration, if that is what is happening (the logic in
DoFileStuff() would have to support this).
2. your catching different types of exceptions. I'm catching any
exceptions and treating them all the same. The show must go on in my
program regardless of any exceptions. Some lines an exception on them
would be best handled by retrying the line and others by skipping to the
next iteration of the program. ie on reading from a server it'd be best
to retry untill it works while on getting a badly formated xml file from
the server I'd probably flag that transaction as questionable and try the
next request.

I wasn't trying to be prescriptive about how your exception handling should
be done. I was just trying to give an example of how Finally is useful.
However, there does seem to be a case for catching some exceptions
separately, and then having a catch-all to cover unexpected exceptions. You
could have

<code>
Sub DoFileStuff()

Try
OpenFile

WriteToFile

Catch ex As SpecificException
' Catch this exception because we know what to do if it occurs

Catch ex As SomeOtherExceptionThatICanHandle
' Catch this exception as well for the same reason. However
' it requires a different reaction, so we catch it separately

Catch ex As Exception
' Catch all other exceptions and perform some
' default action and try to keep going

Finally
If FileIsOpen Then
CloseFile
End If

End Try

End Sub
</code>

Charles
 
You can get line numbers, but that is only good for showing error
messages. It's not like you can in code figure out which function call
caused the error - unless you start hard coding if statements to look
for specific line numbers - but that isn't something you would ever
want to do.

cj wanted to figure out which line of code was causing the problem, to
presumably either have different error handling code, or ignore the
error, etc. That isn't something the stack trace information can
realistically help with.

I think we can agree that using the old On Error GOTO...Resume Next method
is far from ideal. Structured exception handling is a better, more robust
mechanism and would be the prefered method. I am not advocating using the
line numbers and ERL(), more-so mentioning that it is possible.
Not to mention, line numbers come up only when compiled in debug mode.

ERR. Sorry. Thanks for playing. I just tested it in VS2005 and the line number
is retained in a release mode when hard coded as in my sample. You do not
get the line numbers in the stack trace, but ERL() will still report the
line number if it is included in the source code. Hence the additional overhead.
I just checked the sample code with Reflector and the VB compiler is adding
a variable to track the line numbers and incrementing it interspersed in
the code, similar to inserting a trace.write method in the body of the code.
Here's the dis-assembled version of the previous sample:

Public Shared Sub Main()
Dim num1 As Integer = 10
num1 = 20
Try
num1 = 30
num1 = 40
Throw New DivideByZeroException
Catch exception2 As DivideByZeroException
ProjectData.SetProjectError(exception2, num1)
Dim exception1 As DivideByZeroException = exception2
num1 = 60
Console.WriteLine(("Error occured in line: " & Conversions.ToString(Information.Erl)))
num1 = 70
ProjectData.ClearProjectError
End Try
num1 = 80
Console.ReadLine

As you can see, it works but is far from elegant and the performance implications
are not good.
 
Thanks.

Charles said:
Hi Cj


The Catch in Button1_Click() catches any exception that 'escapes' from
DoFileStuff(). So, if UnexpectedException is thrown it will be caught in
Button1_Click(). If SomeException is thrown it will be caught in
DoFileStuff(). If DoFileStuff() rethrows it, or throws it as some other
exception, then that will be caught in Button1_Click(). Otherwise,
DoFileStuff() can consume the exception and retry the offending code or move
on to the next iteration, if that is what is happening (the logic in
DoFileStuff() would have to support this).


I wasn't trying to be prescriptive about how your exception handling should
be done. I was just trying to give an example of how Finally is useful.
However, there does seem to be a case for catching some exceptions
separately, and then having a catch-all to cover unexpected exceptions. You
could have

<code>
Sub DoFileStuff()

Try
OpenFile

WriteToFile

Catch ex As SpecificException
' Catch this exception because we know what to do if it occurs

Catch ex As SomeOtherExceptionThatICanHandle
' Catch this exception as well for the same reason. However
' it requires a different reaction, so we catch it separately

Catch ex As Exception
' Catch all other exceptions and perform some
' default action and try to keep going

Finally
If FileIsOpen Then
CloseFile
End If

End Try

End Sub
</code>

Charles
 
I guess I'll have to do some reading on finally. I'm still not sure I
see the use. Perhaps it's how I'm using try catch. My purpose in
using try catch is that without it, or some other error handling, if a
command throws an exception the program halts with some garbage on the
screen. I've written my program with try catch around statements like
calls to other servers where something like a cable being cut might
cause the line to throw and exception as it can not execute. In the
catch I want to know what command is giving the problem. That'll help
me know what is wrong. I print a custom message to indicate what code
is being executed and the ex.message info to the screen for diagnosis.
I need to know which stored procedure will not work, or is it the
request to the remote server or did it try to parse the xml file and
find out it wasn't a xml file? The presence of an error like this can
mean skip the current record or it might mean reattempt the failed
command until it starts working.

As COR indicated, the finally block should be used to close resources and
do other necessary cleanup to get your program back to a valid state. You
would want to make sure to clean the resources regardless of whether a exception
is thrown. Consider the following pseudocode:

dim cn as new Connection
try
cn.open
catch
messagebox.show("Problem opening connection")
end try

cn.dispose
cn.close

In this case, the connection (an expensive resource) is left open if the
exception is thrown. As an alternative, you can do the following

dim cn as new Connection
try
cn.open
catch
messagebox.show("Problem opening connection")
finally
cn.close
cn.dispose
end try

In this case, we are assured that the connection will be closed. Starting
with VB2005, we can change this as follows:

Using cn as new Connection
try
cn.open
catch
messagebox.show("Problem with connection")
end try
end using

Now we are assured that the connection is properly handled as the Using block
handles the dispose for us and closes the connection. Now, if we want to
simply let the exception bubble up to a calling method, we can trim this
down to:

Using cn as new Connection
cn.open
end using

An exception will still be thrown, but the resource will be released correctly.

Jim Wooley
http://devauthority.com/blogs/jwoole
 
Give me an example of an exception that could be thrown that still
allowed the db connection to open. Honestly, I'd like to know. I'm
sure there are some but it seems to me the most likely reason that line
would throw and exception is it couldn't open the db.

second, assume it didn't open the db and then you fall to the finally
section and you try to close a db that isn't open. wouldn't this also
throw and exception?
 
Give me an example of an exception that could be thrown that still
allowed the db connection to open. Honestly, I'd like to know. I'm
sure there are some but it seems to me the most likely reason that
line would throw and exception is it couldn't open the db.

second, assume it didn't open the db and then you fall to the finally
section and you try to close a db that isn't open. wouldn't this also
throw and exception?

Ok, I was afraid someone would catch that one. I was trying to be terse while
illustrating the finally portion. Is the following better:
 
At least it must not have been a dumb question. These possible errors
are turning into a vicious loop in my head.

Unfortunately I don't get how your line addition helps things.

I'll have to add this to the many areas to research when I get time.
 
CJ,

So my code
after the try catch always executes--how is that different from being in
finally?
Put as first statement in your try catch finallly a return (direct after the
try), and debug it, than you see it.



Cor
 
I was speaking about using the StackTrace and getting line numbers, not ERL.
I never mentioned it, and I've never heard of it. And sort of glad I
hadn't - seems like a horrible way to let people check which line number
caused an error, and hard coding line numbers in their error handling code.
 
At least it must not have been a dumb question. These possible errors
are turning into a vicious loop in my head.
Unfortunately I don't get how your line addition helps things.

Ok. In the new addition, there is some other exception that is thrown other
than creating the connection. It could be due to a null in the database that
is not handled by the data reader, a column that is removed from the database,
a database timeout, anything. The key here being, you need to reclaim the
resource and not just leave it hanging. The best ways to do this are in the
Finally block or with the Using statement.

Jim Wooley

 
dim cn as new Connection
try
cn.open
catch
messagebox.show("Problem opening connection")
end try

cn.dispose
cn.close

In this case, the connection (an expensive resource) is left open if the
exception is thrown.

No it isn't. The code following the End Try will execute. Bad example in
several ways: if an exception is thrown then one presumes that the
connection failed to open, so no resource is used. But, in any case, the
code following the End Try will execute, so if the connection had opened and
then thrown an exception, it would have been disposed and closed.

[Finally, surely the connection should be closed and then disposed]

Charles
 
you could have several catch statements - If each line could throw a
different type of exception, then the appropriate catch statement would be
used.
following is cut-n-paste from msdn
Try
NextCentury = DateAdd("yyyy", 100, GivenDate)
Catch ThisExcep As System.ArgumentException
' At least one argument has an invalid value.
Catch ThisExcep As ArgumentOutOfRangeException
' The result is later than December 31, 9999.
Catch ThisExcep As InvalidCastException
' GivenDate cannot be interpreted As a date/time.
Catch
' An unforeseen exception has occurred.
Finally
' This block is always executed before leaving.
End Try
 
Back
Top