try/catch block design. Two approaches, which one's best?!

M

Mr Flibble

Hi all, happy Friday! (certainly Friday is a day worth celebrating).

I have a question on try/catch design (an exciting Friday topic for sure):

I can either put a try/catch block in every function and have each one
of those handle and log the error in some way (I'm thinking of using
log4net), or I can still have a try/catch block in every function but in
each I simply re-throw the error attaching the object to the inside
(creating an error stack) and then just have some "top level" block
catch and log the error (by looking through the stack to determine the
cause of the exception).

If I choose to do it the latter way, I'll have to make sure my error
objects contain all the details (variables) that I may need to inspect,
whereas if I do it the former way, I would obviously have all this
information available to me locally where the exception actually occured.

I'm at a loss over which is better/best practice.

Can anyone please advise which is the better approach?

Many thanks,

Mr Flibble
 
F

Frans Bouma [C# MVP]

Mr said:
Hi all, happy Friday! (certainly Friday is a day worth celebrating).

I have a question on try/catch design (an exciting Friday topic for
sure):

I can either put a try/catch block in every function and have each one
of those handle and log the error in some way (I'm thinking of using
log4net), or I can still have a try/catch block in every function but
in each I simply re-throw the error attaching the object to the inside
(creating an error stack) and then just have some "top level" block
catch and log the error (by looking through the stack to determine the
cause of the exception).

If I choose to do it the latter way, I'll have to make sure my error
objects contain all the details (variables) that I may need to
inspect, whereas if I do it the former way, I would obviously have
all this information available to me locally where the exception
actually occured.

I'm at a loss over which is better/best practice.

Can anyone please advise which is the better approach?

this is bad practise:
try
{
// some code
}
catch(SomeExceptionType ex)
{
throw ex; // A
}

as at point A, the stacktrace is gone, the exception will originate
from point A.

In short, only place try/catch blocks in code if you're actively DOING
something with the exception at that spot. Otherwise don't place a
catch clause there, it will result in that the exception is bubbled up
nicely WITH stacktrace.

FB


--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
K

Kevin Spencer

Actually, if you use a throw statement with no expression (throw;), the
stack trace is preserved at the originating point of exception. MSIL has 2
different instructions for "throw" - "throw" and "rethrow". When you use
"throw" in C# and an expression (throw ex;), it is compiled to the MSIL
"throw" instruction, which does not preserve the stack trace. But without an
expression, it is compiled to the MSIL "rethrow" which preserves the stack
trace at the originating exception point.

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Chicken Salad Alchemist

A lifetime is made up of
Lots of short moments.
 
M

Mr Flibble

* Kevin Spencer said:
Actually, if you use a throw statement with no expression (throw;), the
stack trace is preserved at the originating point of exception. MSIL has 2
different instructions for "throw" - "throw" and "rethrow". When you use
"throw" in C# and an expression (throw ex;), it is compiled to the MSIL
"throw" instruction, which does not preserve the stack trace. But without an
expression, it is compiled to the MSIL "rethrow" which preserves the stack
trace at the originating exception point.

So if one method of throwing includes a stack trace and the other
doesn't why would you use the one which doesn't?
 
M

Marc Gravell

Not quite there...

It is about preserving the *original* stack trace, versus seeing a stack
trace that only goes as far as your handler;

Imagine the exception is thrown 27 levels down, and you catch it at the 15th
level; if you "throw", then the stack-trace still shows the route to the
original 27th level method - which allows you to inspect an exception,
decide its none of your business, and throw it as though you didn't look. If
you "throw ex" (even with the original ex), then it now only shows the route
to the 15th level.

Marc
 
J

Jesse Houwing

Mr said:
So if one method of throwing includes a stack trace and the other
doesn't why would you use the one which doesn't?

You'd use the one that removes the stacktrace if:
- you've already logged it somewhere
- you don't want your caller to see your internals
- you've wrapped the exception in a new exception and are throwing that
exception instead
- you are throwing another exception instead that would make more sense
to your caller.

Jesse Houwing
 
K

Kevin Spencer

That's what I do. With certain business classes, I include logging, and
throw exceptions. These are then caught and possibly handled by the client
object. The logging can be configured as turned on or turned off.

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Chicken Salad Alchemist

I recycle.
I send everything back to the planet it came from.
 
G

Guest

Some related general exception handling best practices:
* Only catch exceptions you know you can safely handle (add logging to the
handler if you want, but if it's "handled" I don't know why you'd care)
* Don't "catch(Exception)" except in a top-level handler just before
termination.

It's in the top-level handler where you'd log uncaught exceptions. For
example, if you have a WinForms application, you could log uncaught
exceptions in the Main method like this:
[STAThread]
static void Main()
{
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
catch (Exception e)
{
System.Diagnostics.Trace.WriteLine(e.ToString());
throw;
}
}

....doing much more than Trace.WriteLine is dangerous because you don't know
the state of your application at that point.
 
J

Joerg Jooss

Thus wrote Mr Flibble,
So if one method of throwing includes a stack trace and the other
doesn't why would you use the one which doesn't?

Usually because you have no other choice.

Some application frameworks (and the BCL itself) feature unhandled exceptions
events or global exception handling methods. If you ever want to propagate
an exception from one of these, you cannot simply
"throw;"
because you're no longer in the original catch block.

Cheers,
 
F

Frans Bouma [C# MVP]

Kevin said:
Actually, if you use a throw statement with no expression (throw;),
the stack trace is preserved at the originating point of exception.
MSIL has 2 different instructions for "throw" - "throw" and
"rethrow". When you use "throw" in C# and an expression (throw ex;),
it is compiled to the MSIL "throw" instruction, which does not
preserve the stack trace. But without an expression, it is compiled
to the MSIL "rethrow" which preserves the stack trace at the
originating exception point.

I should have pointed that out indeed, sorry about that, and thanks
for this addition, Kevin :)

FB

--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top