Try...Catch...Finally

  • Thread starter Thread starter Tyrant Mikey
  • Start date Start date
T

Tyrant Mikey

Question for all you MVPs:

Is the Catch block required in a Try...Catch...Finally block? If not,
what happens when an exception occurs inside a Try block?

For instance, consider the following code:

Public Shared Function Load(ByVal censusDate As Date) As Census

Dim proc As New
SelectCensusByDateProcedure(Common.GetOpenConnection())
Dim row As New Census
Dim rdr As SqlDataReader

Try
proc.CensusDate = censusDate
rdr = proc.ExecuteReader()
If rdr.Read Then
row = New Census(rdr)
End If
Finally
If Not rdr Is Nothing Then
rdr.Close()
End If
proc.Dispose()
End Try

Return row

End Function


I have a guess as to what happens, based on observation. I think that
if an exception occurs in the Try block, the Finally block is
immediately called, and then the exception is raised to the caller.

Can someone please verify that this is valid, and whether or not it's
an acceptable approach? I really hate having to write the following:

Try
proc.CensusDate = censusDate
rdr = proc.ExecuteReader()
If rdr.Read Then
row = New Census(rdr)
End If
Catch ex As Exception
Throw ex
Finally
If Not rdr Is Nothing Then
rdr.Close()
End If
proc.Dispose()
End Try

I did it for a long time because I didn't know for sure if it was safe
to omit the Catch block. I'd like some confirmation that it's okay.

Thanks.
 
Catch isn't required. Catch _OR_ Finally is required. However, when you
don't use Catch and an exception occurs, the error handlers start up the
stack looking for a suitable handler. What I don't know is if the Finally
blocks found along the way are executed.

Mike Ober.
 
Hrm. Sounds like I need to write a quick program to test that, and
determine what it does. I'll do that today and let you know what it
does.
 
What I don't know is if the Finally
blocks found along the way are executed.
all finally blocks are executed according to scoping rules.
I really hate having to write the following:
Why is that? the code and the approach seem perfectly ok to me - unless i am
missing something major.

--
Regards,
Alvin Bruney [MVP ASP.NET]

[Shameless Author plug]
The Microsoft Office Web Components Black Book with .NET
Now Available @ www.lulu.com/owc
Forth-coming VSTO.NET - Wrox/Wiley 2006
 
I really hate having to write the following:

Why is that? the code and the approach seem perfectly ok to me - unless i am
missing something major.

Truthfully, it's because I'm lazy. :0)

Also, it seems like I'm catching an exception *just* so I can rethrow
it without doing anything with it. To me, that smacks loudly of a bad
habit. I was taught that you should never catch any exception you don't
know how to handle (the exception to the rule being some top-level
handler that catches everything gracefully). So what I'd like to do is
wrap the code in a Try block, include a Finally clause for cleanup, and
let the caller catch the exception and do something with it.
 
right that's fine. i saw the throw and assumed you were doing something with
the exception. that's good practice.

--
Regards,
Alvin Bruney [MVP ASP.NET]

[Shameless Author plug]
The Microsoft Office Web Components Black Book with .NET
Now Available @ www.lulu.com/owc
Forth-coming VSTO.NET - Wrox/Wiley 2006
 
Alvin said:
What I don't know is if the Finally
all finally blocks are executed according to scoping rules.
But, you should be aware that filters higher up the callstack may be
executed before the finally block - thus, if you need the finally block
to ensure that security rules are being followed, you need to be *very*
sure of your call stack.

Damien
 
Also, it seems like I'm catching an exception *just* so I can rethrow
it without doing anything with it.

OT but beware that in your example you are not simply rethrowing the
exception but also reseting its stack trace (unless VB behaves in a
different way as C# but i don't think so), hence hiding the origin of the
exception. This may cause you nasty surprises if you are not aware of it.
Use Throw alone to rethrow an exception.
 
you can avoid to use catch.

Besides note that call "throw ex" resets stack trace of the exception.
So, when you catch the exception, exception.Stack ends with Load(),
not with the function that realy throwed it.

I hope I was clear (I know, my english is terrible).
 
But, you should be aware that filters higher up the callstack may be
executed before the finally block - thus, if you need the finally block
to ensure that security rules are being followed, you need to be *very*
sure of your call stack.
And that is exactly what scoping rules determine.

--
Regards,
Alvin Bruney [MVP ASP.NET]

[Shameless Author plug]
The Microsoft Office Web Components Black Book with .NET
Now Available @ www.lulu.com/owc
Forth-coming VSTO.NET - Wrox/Wiley 2006
 
Cool. Not only do I get to be lazy, I get to be lazy while doing
something the right way.

How's THAT for cool?!
 
Yikes! That's scary!

However, I'm having a tough time wrapping my brain around when this
would actually be useful, and how hyped up I should be about it. If my
software is for internal use only, it's a fair assumption that I *know*
who's calling me. If I don't, we're screwed anyway!

Now, if you're writing publicly available class libraries, that's a
different story.

Thoughts?
 
Tyrant said:
Yikes! That's scary!

However, I'm having a tough time wrapping my brain around when this
would actually be useful, and how hyped up I should be about it. If my
software is for internal use only, it's a fair assumption that I *know*
who's calling me. If I don't, we're screwed anyway!

Now, if you're writing publicly available class libraries, that's a
different story.

Thoughts?

Yeah, I'm lucky too. At present, all of the software I write is only
for use within the same company (however, we may in the future start
selling parts of our software). There's still the Yikes factor if
you're relying on finally to leave stuff in a consistent state, and the
filter also relies on the same stuff being consistent. Just one to tuck
away into the back-brain for now, until I'm banging my head against the
monitor debugging something like this.

Damien
 
Michael said:
Catch isn't required. Catch _OR_ Finally is required.

Seems like there are so many times when you have:

try
{
do stuff
}
catch {}

that:

try
{
do stuff
}

should be valid; ie.g. no catch or finally.

Hilton
 
Hilton said:
Seems like there are so many times when you have:

try
{
do stuff
}
catch {}

that:

try
{
do stuff
}

should be valid; ie.g. no catch or finally.

But if there's no catch, it certainly *isn't* equivalent to the above,
in the most obvious reading.

Also, the first block should be very rare indeed - at any *absolute*
minimum I usually insist on a comment to explain why I don't care even
to the extent of logging the exception.
 
The first example would be close to the VB 6 construct "On Error Resume
Next", which can be extremely useful, especially when setting up an
environment for a program. Sometimes the environment is already there, in
which case the errors can safely be ignored.

Mike Ober.
 
Michael said:
The first example would be close to the VB 6 construct "On Error Resume
Next", which can be extremely useful, especially when setting up an
environment for a program. Sometimes the environment is already there, in
which case the errors can safely be ignored.

Mike Ober.
We banned "On Error Resume Next" in our shop - it just seems too much
of an assumption that you know all possible errors that might have
occurred, and none of them could possibly cause problems for the code
that follows. We did allow the following:

On Error Goto <ErrHandler>
<Potentially unsafe code>
:
:
:
<ErrHandler>:
If Err.Number = <The error that it's safe to ignore> Then Resume Next

Pretty much the same goes for Try..Catch - Using Catch Ex as Exception
may be a quick way of supressing exceptions for a particular piece of
code, but I feel it goes too far - you're saying that absolutely
anything is fine, you'll be able to carry on. Yippee when the
StackOverflowException hits that.

If you know a particular exception is likely with your code, and that
it's fine, catch that specific exception. Let the rest bubble up to
where they're meant to go. This is also why it's best to define new
exceptions for exceptional behaviour in your own code rather than just
always throwing an Exception("I'll describe the problem here").
Otherwise, you tend to have silent failures which your program doesn't
handle, but no-one knows anything about (until 6 months later when the
S**t hits the fan)

Damien
 
The only place I use On Error Resume Next is when I'm doing something along
the lines of:

CreateDir("c:\path1")
createdir("c:\Path1\path2")

etc.

If Path1 already exists, I don't care about the error, but the second
statement will fail by itself if Path1 doesn't already exist. Thus my
statement that it's useful when configuring the runtime environment.
Fortunately, VB 2005's My class cleanly handles this type of issue, making
the need for On Error Resume Next obsolete.

Mike.
 
Back
Top