Choosing Exception objects

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Hi,
This might seem like a strange question but I'm wondering how other
developers go about choosing the appropriate Exception objects to use in
their catch statements. Currently, I choose them only when they are returned
in the error message of an unhandled exception, then set a general exeption
handler to deal with anything else that might happen. This doesn't seem the
best way, but maybe it is(?). Should I get to know the names of all the
exception objects & pre emptively add them into my catches? If so, is there a
hierachy of them to make them easy to find in the System.namespace? They seem
only to be grouped alphabetically with all the other System objects. Hope
this makes sense.

Thanks very much for your opinions
Ant
 
You should typically, IMO, catch exceptions that you are prepared to handle.
The rest you should let bubble up. For instance, if you are doing an
int32.parse operation, you should first find out what exceptions are thrown.
If you intend to handle those, you put them in your catch block
(argumentnullexception and/or nullexception) and then you let other
exceptions bubble to the top. As a general rule, you should stay away from
catching all exceptions - there are exceptions to this exception rule as in
the case of library development etc.

--
Regards,
Alvin Bruney - ASP.NET MVP

[Shameless Author Plug]
The Microsoft Office Web Components Black Book with .NET
Now available @ www.lulu.com/owc, Amazon.com etc
 
Ant,

The question you probably need to ask at each level in the calling stack
trace is, if any exceptions are thrown, which, if any, do I want to catch
here?

The type of exception that is to be used depends on what you want to do when
you catch an exception. It's pretty pointless to have five or six catches
for different exception objects when they all do the same thing. But if you
want to perform some action as a result of a certain exception being thrown,
then you know you need to set up a catch for this.

Rather than knowing all the available exception objects, you should look at
the objects your using in the try statement, and see what exceptions they
could return... For example, if trying to connect to a database with the
SqlClient, you could catch why the command that was executed on the database
failed by catching the SqlException object, and evaluating SQL specific
errors (which server, procedure etc the error occurred on).

For more google on it.
(http://www.google.co.uk/search?hl=en&q=exception+handling+c#)

Hope this helps.

Dan.
 
Ant said:
Thanks very much. That made good sense.
Regards
Ant

I liked what Anders Hjelsberg said about the try/catch/finally mechanism.

It's not about try/catch but try/finally. He ment that good code has a
try/finally ratio of 10:1 to try/catch.
Not sure this is true for managed runtimes like C# (especially with the
using statement). But try do some Delphi and you'll see that try/finally is
almost everywhere (as you need to destroy every object yourself).

Also, I don't mind empty-catching stupid exceptions. For me, code like below
is The Good Thing.

int i = 0;
try
{
i = Convert.ToInt32(myStringValue);
}
catch {}

In our shop we use the 'catch {}' on one line to signal that the exception
is supposed to get eaten and that nothing is forgotten as there is no code
intented for that block.

Happy Coding
- Michael S
 
Also, I don't mind empty-catching stupid exceptions. For me, code like
below
is The Good Thing.

int i = 0;
try
{
i = Convert.ToInt32(myStringValue);
}
catch {}

In our shop we use the 'catch {}' on one line to signal that the exception
is supposed to get eaten and that nothing is forgotten as there is no code
intented for that block.

This can work for a time but what is when inside of that codeblock an
outofmemoryexception occures? or a stackoverflow? or even if myStringValue
is a property if you have a nullreferenceexception in that property? That
will all get swallowed and nobody will even notice.

I once had the problem because I couldn't login into my program. The reason
wasn't that it couldn't connect to the database, but there was a
classloadexception because of a missing assembly or wrong version of the
assembly. It took some time until we discovered that this was the problem.
If we had caught a databaseexception instead of System.Exception we'd see
the problem immediately.
 
Michael S said:
I liked what Anders Hjelsberg said about the try/catch/finally mechanism.

It's not about try/catch but try/finally. He ment that good code has a
try/finally ratio of 10:1 to try/catch.
Not sure this is true for managed runtimes like C# (especially with the
using statement).

I think it probably should be true of C# too, if you just accept that
using *is* a try/finally block.

Heck, if you include lock in there the ratio would go even higher :)
 
cody said:
This can work for a time but what is when inside of that codeblock an
outofmemoryexception occures? or a stackoverflow? or even if myStringValue
is a property if you have a nullreferenceexception in that property? That
will all get swallowed and nobody will even notice.

Well, I refer to Anders Hejlsberg again.
He mention exactly the above exceptions as exemples of what never to catch
as there is no espace.
If there are no more memory you have a poor design or a really poor
computer. If you get a stack overflow you have a serious bug in conjunction
with a poor design.

Exceptions are not ment for catching bugs or poor designs.

But I get what your aiming at. And I agree.

I would not like to have code full of empty catch-blocks as the code is hard
to debug for the reasons you mention. But I was talking about catching
stupid exceptions as in my example above. I think the best approach is (what
we have done) to have a Utility class with a .ToInt32Def(Object o, int
default) that never throws an exception. I like how C# have using and the as
keywords to minimize the use of try-blocks.

2 more cents
- Michael S
 
Jon Skeet said:
I think it probably should be true of C# too, if you just accept that
using *is* a try/finally block.

Heck, if you include lock in there the ratio would go even higher :)

Sure.

But I think the beauty of C# is that (correctly used) it removes a lot of
try-blocks.

To compare with Delphi: In Delphi most methods must (should) contain a
try/finally to free local objects.
Also Delphi has the poor language design if seperating try/finally and
try/except which makes for a lot of nested try blocks. In Delphi it is hard
to spot actual exception-handling from protection as all these try blocks
makes you blind.

In my resent C# project there is not one try-finally. I rely on using, is
and as. It's beautiful.

Happy Coder
- Michael S
 
In our shop we use the 'catch {}' on one line to signal that the
Well, I refer to Anders Hejlsberg again.
He mention exactly the above exceptions as exemples of what never to catch
as there is no espace.
If there are no more memory you have a poor design or a really poor
computer. If you get a stack overflow you have a serious bug in conjunction
with a poor design.

Please reread my post I never said that you should catch them, I said you
shouldn't swallow them because you may hide serious bugs this way.
 
To compare with Delphi: In Delphi most methods must (should) contain a
try/finally to free local objects.
Also Delphi has the poor language design if seperating try/finally and
try/except which makes for a lot of nested try blocks. In Delphi it is hard
to spot actual exception-handling from protection as all these try blocks
makes you blind.

In my resent C# project there is not one try-finally. I rely on using, is
and as. It's beautiful.

The "using" clause *is* a "try/finally" and nothing else..
 
cody said:
Please reread my post I never said that you should catch them, I said you
shouldn't swallow them because you may hide serious bugs this way.

Please rerad my post and you'll see that I AM talking about swallowing them.
But I think we agree cody. Let them bubble up but swallow the lame ones.

- Michael S
 
cody said:
The "using" clause *is* a "try/finally" and nothing else..

I know that cody. Please! Since when have you demoted me to idiot?

I am talking about high level C# syntax and not CIL. My whole point is that
you remove a lot of try-blocks with C#. Try doing code in Delphi.NET and you
got a lot more try-blocks. Tjeesus.

Unhappily Misunderstood
- Michael S
 
int i = 0;
try
{
i = Convert.ToInt32(myStringValue);
}
catch {}

I can't think of a scenario why you'd ever want to do this...
If your string object is null, empty, not a number, etc should surely all be
treated differently, even if it's alerting the user (or logging this
problem) that this is the case.
 
In my resent C# project there is not one try-finally. I rely on using,
is
I know that cody. Please! Since when have you demoted me to idiot?

Please calm down, nobody said that.
I am talking about high level C# syntax and not CIL. My whole point is that
you remove a lot of try-blocks with C#.

Yes indeed, (almost) all classes that require manual cleanup implement
IDisposable, therefore you rarely need finally in C#.
Try doing code in Delphi.NET and you got a lot more try-blocks. Tjeesus.

Iam sure about that :)
 
Dan Bass said:
I can't think of a scenario why you'd ever want to do this...
If your string object is null, empty, not a number, etc should surely all
be treated differently, even if it's alerting the user (or logging this
problem) that this is the case.

Well, I can think of several scenarios.
A simple example would be for a web application where you want to list
stuff. The url may be

/ListStuff.aspx?stuffId=57

The code behind to list stuff would be above:

int stuffId = 0;
try
{
stuffId = Convert.ToInt32(Request.QueryString["stuffId"]);
}
catch {}
DataSet myStuffDS = ListStuff(stuffId);

With this you get alot of error handling for free. If the querystring is
broke or tampered with; stuffId will be zero, which will (with proper
primary-keys) yield a list of zero items from a datasource and display
nothing.
- No Exceptions needed, No error page needed to be coded and no animals
harmed in the process.

However, by the use of utility classes the code would probably look more
like this:

int stuffId = RequestManager.QueryString.AsInteger("stuffId", 0); // Do I
come from a Delphi background or what? =)

I can think of several more different examples.
But I won't let your lack of imagination ruine my simple code and
profitability. =)

Keep it as simple as possible, but no simpler.
- Michael S
 
int stuffId = 0;
try
{
stuffId = Convert.ToInt32(Request.QueryString["stuffId"]);
}
catch {}
DataSet myStuffDS = ListStuff(stuffId);


I'd always be more inclined to do this...


//---------------------------------------------------

int stuffId = GetStuffId ( "stuffId" );

.....

int GetStuffId ( string index )
{
int valueInt = 0;
string valueString = Request.QueryString[index ];
if ( valueString!= null && valueString!= "" )
{
valueInt = Int32.Parse ( valueString );
}
return valueInt;
}

//---------------------------------------------------


probably because I guess I'm not used to thinking of exceptions as way of
handling errors, but of catching unexpected errors.

If valueString came back as not a number, something's wrong somewhere, and
so when the exception is caught at a higher level in the stack, it is
reported as necessary there. The fact that a try/catch surrounds the
conversion means you loose this.

It's all knit-picking I know, but I'm just interested on learning others
approach to things. =o)

Dan.
 
"Dan Bass" <Not Listed> wrote in message

Hi Dan.

You must have read way to much about 'design by contract'.
- The callie should define what is ok and not the caller.

Well, that was borned out of Eiffel and have gained grounds in the Java
world as well, but it is soon becoming a nightmare. We really liked making
coding into engineering until we realized it is actually not.

In my example of calling Request.QueryString, and applying contracts, it
should fail as the contract says that stuffId must be 'a valid primary key
for stuff'. Hence 0 and 'qwerty' is in violation to the contract.

But I don't care about the freakin' contract. My code is cool about these
things. Hence the ListStuff returns an empty list if you supply a invalid
parameter. Not null and not an exception.

The problem for the caller is what to do with null or an exception. It can
make little sense of an exception.
What would you do? Let it bubble up all the way to the user? Log it? Eat it?
Why?

I can think of a few whys. But then they should be part of the specs and not
coded for free.

Happy Contractions
- Michael S
 
The problem for the caller is what to do with null or an exception. It can
make little sense of an exception.
What would you do? Let it bubble up all the way to the user? Log it? Eat
it? Why?

Ah but would a blank list be more helpful than a well used exception? I
think not. ;o)
 
Back
Top