The problem with Try Catch Finally...

  • Thread starter Thread starter VB Programmer
  • Start date Start date
V

VB Programmer

Variable scope doesn't make sense to me when it comes to Try Catch Finally.

Example: In order to close/dispose a db connection you have to dim the
connection outside of the Try Catch Finally block. But, I prefer to dim them
"on the fly" only if needed (save as much resources as possible). A little
further... I may wish to create a sqlcommand and datareader object ONLY if
certain conditions are met. But, if I want to clean these up in the Finally
then I am FORCED to declare them above the Try.

Why???
 
Why not declare them and just CREATE them when you need to. After all,
that's what may take the longest.

- Jeff
 
Well, you are most of the way there in your description. Variables are local
to the scope they are declared in, and scope is determined by code block.
Any time you have a code block, you can declare local variables in that
block. This is true for try - catch - finally, if, while, or anything other
similar construct. This enables you to declare a new variable inside that
block, and have it marked for GC once you exit that code block.

What it means for you in terms of your try - catch is that you need to code
around how you create it. First of all, declaring a variable doesn't
allocate space for it, so you don't have to worry about that. You may also
want to re-think what you are enclosing in a try-catch block. You don't need
to wrap huge chuck of code in such a block - you just need to wrap a
dangerous operation that might throw an exception in such a block. So,
declare, prepare, then when you execute the risky operation, wrap it in a
try-catch. I seldom have more than a couple of lines of code in a try block,
and usually have exactly one.
 
You mentioned "I seldom have more than a couple of lines of code in a try
block, and usually have exactly one." Is this standard? In VB6 I've
always

No, that is not the standard. I, for example, will put all of the code in a
method inside a try/catch block, and then put additional try/catch blocks
and conditional code inside that outer block to catch specific errors. The
outside one is for anything I might have missed. How you use it is up to
you, and what your needs are.
What is considered "risky operation"? Connecting to db, filling datasets,
datareaders, etc...?

That's a difficult question to answer (which is why I wrap all of my method
code in an outer try/catch block). Any operation which might cause your
program to malfunction is risky.

The bottom line is (and everyone here seems to agree on this), declare your
variables outside of the block, and assign them inside the block.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
http://www.takempis.com
Complex things are made up of
lots of simple things.
 
And one other thing I should mention, in case you don't understand. The
problem you experienced was due to referencing variables declared inside the
try/catch block from the Finally block. The Finally block executes
regardless of whether an error occurs or not. That means that it must be
able to access the variables used in it regardless of whether they were
assigned or not. When you declare a variable inside the try block, your code
might never reach the declaration before execution falls through to the
catch block. Therefore, any variable referenced in the Finnally block must
be declared prior to the Try block.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
http://www.takempis.com
Complex things are made up of
lots of simple things.
 
Folks, I cant beleive how long this thread has become !

When we are old and grey, we can enchant our grandchildren with stories of
how we spent our precious youth talking about Try Catch blocks !

Sorry, couldnt resist that, keep smiling :)
 
Good stuff! :)

Terry Burns said:
Folks, I cant beleive how long this thread has become !

When we are old and grey, we can enchant our grandchildren with stories of
how we spent our precious youth talking about Try Catch blocks !

Sorry, couldnt resist that, keep smiling :)
 
You mentioned "I seldom have more than a couple of lines of code in a
try
always
No, that is not the standard. I, for example, will put all of the code in a
method inside a try/catch block, and then put additional try/catch blocks
and conditional code inside that outer block to catch specific errors. The
outside one is for anything I might have missed. How you use it is up to
you, and what your needs are.

I would never go so far as to put all of the code inside of a method inside
of a try-catch block, because then you are never really sure what you are
catching. Sure, you could simply catch a System.Exception, but if you don't
know what you're catching, and as a result can't react appropriately, you
probably don't want to just sit on that error instead of passing it up
through the call stack.

With VB6, you just had to universally set up an onerror statement that
caught all errors, and then go through and figure out what happened and what
to do about it. The beauty of try-catch is that you can wrap specific
statements and handle it appropriately.

Let's do an example - open up a SQL Server connection, set up a command
object, and execute that command object:

----
SqlConnection connMyConnection = new SqlConnection(szConnectionString);
SqlCommand cmdMyCommand = new SqlCommand("MyCommand", connMyConnection);
cmdMyCommand .CommandType = CommandType.StoredProcedure;
cmdMyCommand .Parameters.Add("@myParameter", SqlDbType.VarChar, 50).Value =
szValue;
connMyConnection.Open();
cmdMyCommand.ExecuteNonQuery();
----

The SqlConnection constructor that I used does not throw an exception, so
there is nothing to catch there.
The SqlCommand constructor that I used does not throw an exception, so there
is nothing to catch there.
Setting the command type could throw an ArgumentException, so you'll want to
catch that.
The add method of the parameters collection doesn't throw an exception, nor
does the Value property of the SqlParameter object, so there is nothing to
catch there.
The Open method of SqlConnection could throw either an
InvalidOperationException or a SqlException, so you'll want to catch that.
The ExecuteNonQuery method of SqlCommand could throw a SqlException, so
you'll want to catch that.

So, you end up with:

----
SqlConnection connMyConnection = new SqlConnection(connectionString);
SqlCommand cmdMyCommand = new SqlCommand("MyCommand", connMyConnection);
try {
cmdMyCommand .CommandType = CommandType.StoredProcedure;
} catch (ArgumentException myArgumentException) {
// do something to react to this - since it's hard coded, you can
probably fix your code and get rid of this check
} finally {
// do some cleanup work
}
cmdMyCommand .Parameters.Add("@myParameter", SqlDbType.VarChar, 50).Value =
szValue;
try {
connMyConnection.Open();
} catch (InvalidOperationException myInvalidOperationException) {
// do something to react to this - since it's hard coded, again you can
probably fix your code and dispense with this check
} catch (SqlException mySqlException1) {
// do something to react to this - either dump to the event log or, if
in debug mode (use preprocessors) write back the message
} finally {
// do some cleanup work
}
try {
cmdMyCommand.ExecuteNonQuery();
} catch (SqlException mySqlException2) {
// do something to react to this - either dump to the event log or, if
in debug mode (use preprocessors) write back the message
} finally {
// do some cleanup work
}
----

If you look up the best practices, you will find it stated in as many words:

"Use try/finally blocks around code that can potentially generate an
exception and centralize your catch statements in one location. In this way,
the try statement generates the exception, the finally statement closes or
deallocates resources, and the catch statement handles the exception from a
central location."

Full list of best practices here:

http://msdn.microsoft.com/library/d...l/cpconbestpracticesforhandlingexceptions.asp

So yes, I would beg to differ. I do consider this a standard. It's what I've
been doing in C++ for years now.

Also, you can check for exceptions before they are thrown. If you are going
to close the aforementioned SqlConnection, instead of just using:

connMyConnection.Close();

use:

if (connMyConnection != null && connMyConnection.State !=
ConnectionState.Closed) {
connMyConnection.Close();
}

And so it goes.


--
Chris Jackson
Software Engineer
Microsoft MVP - Windows XP
Windows XP Associate Expert
--
 
A risky operation is anything that could raise an exception. When calling a
method check the help on it. It will list any exceptions that it raised and
the conditions to cause the exception.

Anytime a risky operation is called place it in the try block, and in the
finally block clean up any resources such as filestreams, database
connections, references to COM objects, etc... In the catch block you
could...

1) propagate the error to the caller
2) wrap that error in a new custom (InnerException) error of your own giving
a more human understandable message and throw to caller
3) log the error and continue with rest of method
4) ignore and do again (entire try-catch-finally in a loop).
5) ignore the error and continue with rest of method.
6) ?? anything you desire

What you do depends on the needs/requirements of your application.
 
I would never go so far as to put all of the code inside of a method
inside
of a try-catch block, because then you are never really sure what you are
catching. Sure, you could simply catch a System.Exception, but if you don't
know what you're catching, and as a result can't react appropriately, you
probably don't want to just sit on that error instead of passing it up
through the call stack.

I'm always sure of what I'm catching, because I use a global error-handler
routine in my outer try/catch block, which logs the Exception message, any
InnerException message, and a Stack trace to the Event Log. This is so that
I can figure out what caused the error and determine how to best handle it
with code.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
http://www.takempis.com
Complex things are made up of
lots of simple things.
 
I'm always sure of what I'm catching, because I use a global error-handler
routine in my outer try/catch block, which logs the Exception message, any
InnerException message, and a Stack trace to the Event Log. This is so that
I can figure out what caused the error and determine how to best handle it
with code.

I am sure this works just fine, and I am not attempting to disparage what
you are doing. But I think this is an example of "extending" the syntax of
try-catch to more closely approximate the behavior of OnErrorGoto from
Visual Basic. While this is certainly creative and effective, I wouldn't
consider it to be a best practice, that's all. You are writing code to
figure out what the error is (presumably using reflection) and react
appropriately. But the beauty of structured exception handling is that you
no longer have to do that, and while you may have templates in place for
creating your applications, somebody who is new to the construct would be
best served by learning the optimal use of said construct.

--
Chris Jackson
Software Engineer
Microsoft MVP - Windows XP
Windows XP Associate Expert
--
 
You totally misunderstand my usage of Try/Catch. If you will review my
original message, you will see that I employ the outer Try/Catch as a means
of catching anything I've missed in the other error-handling code I put into
my code. It is a way of catching things I haven't thought of, so that I can
fix them with proper error-handling. And Reflection has nothing to do with
it, unless you consider a Stack Trace some form of Reflection.

In the real world, one doesn't have the time to spend to make software
perfect. One has to compromise. If I had all the time in the world, I could
write the perfect software, and it would never misbehave. However, even
Microsoft, with all of it's money and resources, doesn't have the time or
the budget to write perfect software. My outer Try/Catch is a means of
identifying problems that are not identified (and may not manifest
themselves in an easily-identifiable manner) so that they can be fixed.
Microsoft has implemented mechanisms, such as Error Reporting, to identify
problems so that they can be fixed as well.

I find it odd that you don't (1) understand what I'm doing, and (2) assume
that, because it is not standard according to your philosophy, it is not a
"Best Practice." Best Practices are developed by people with a lot of hard
experience, and philosophizing about software doesn't create them.
Experience does.

I can tell you this: I write a lot of robust, pretty-well-optimized
software. It does what it is intended to do, with a very small percentage of
failure. Regardless of the characterization that you may put upon my
practices, I think that whether or not they achieve that goal is the best
measure of them.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
http://www.takempis.com
Complex things are made up of
lots of simple things.
 
Michael Lang said:
A risky operation is anything that could raise an exception. When calling a
method check the help on it. It will list any exceptions that it raised and
the conditions to cause the exception.

What do you do when the method changes, adding new exceptions?
 
Both of you are right.
With the structure exception handling, we need do as Chris does. But with
the other unhandle expection, we need to do it in the outer most procedure,
may not within the same function.


Kevin Spencer said:
You totally misunderstand my usage of Try/Catch. If you will review my
original message, you will see that I employ the outer Try/Catch as a means
of catching anything I've missed in the other error-handling code I put into
my code. It is a way of catching things I haven't thought of, so that I can
fix them with proper error-handling. And Reflection has nothing to do with
it, unless you consider a Stack Trace some form of Reflection.

In the real world, one doesn't have the time to spend to make software
perfect. One has to compromise. If I had all the time in the world, I could
write the perfect software, and it would never misbehave. However, even
Microsoft, with all of it's money and resources, doesn't have the time or
the budget to write perfect software. My outer Try/Catch is a means of
identifying problems that are not identified (and may not manifest
themselves in an easily-identifiable manner) so that they can be fixed.
Microsoft has implemented mechanisms, such as Error Reporting, to identify
problems so that they can be fixed as well.

I find it odd that you don't (1) understand what I'm doing, and (2) assume
that, because it is not standard according to your philosophy, it is not a
"Best Practice." Best Practices are developed by people with a lot of hard
experience, and philosophizing about software doesn't create them.
Experience does.

I can tell you this: I write a lot of robust, pretty-well-optimized
software. It does what it is intended to do, with a very small percentage of
failure. Regardless of the characterization that you may put upon my
practices, I think that whether or not they achieve that goal is the best
measure of them.

--
HTH,

Kevin Spencer
Microsoft MVP
.Net Developer
http://www.takempis.com
Complex things are made up of
lots of simple things.

handle
 
I agree, where would brain surgery machine coders be without a copy of Z:
for surgeons and the latest version of .NET. Perhaps . . . .

On Error Resume Next

Dim FrontalLobe as lobe

FrontalLobe=Brain.getFrontalLobe()

if Not ( FrontalLobe is nothing ) then

'. . .
end if

'As you can see I'm really bored !!
 
You totally misunderstand my usage of Try/Catch. If you will review my
original message, you will see that I employ the outer Try/Catch as a means
of catching anything I've missed in the other error-handling code I put into
my code. It is a way of catching things I haven't thought of, so that I can
fix them with proper error-handling. And Reflection has nothing to do with
it, unless you consider a Stack Trace some form of Reflection.

I don't believe that I misunderstand it at all. In fact, I believe I
acknowledged that I am sure it is both creative and effective. What you are
doing is, objectively, emulating a VB6- construct. There is nothing wrong
with that - it worked for quite a few versions of VB and VBScript. That
doesn't make it structured exception handling, but it does make it yet
another tool in your tool belt.
In the real world, one doesn't have the time to spend to make software
perfect. One has to compromise. If I had all the time in the world, I could
write the perfect software, and it would never misbehave. However, even
Microsoft, with all of it's money and resources, doesn't have the time or
the budget to write perfect software. My outer Try/Catch is a means of
identifying problems that are not identified (and may not manifest
themselves in an easily-identifiable manner) so that they can be fixed.
Microsoft has implemented mechanisms, such as Error Reporting, to identify
problems so that they can be fixed as well.

Absolutely. You simply take a different approach. After having worked with
the framework a long time, most of what I do I have seen before. I wrap the
calls I know throw exceptions, and handle them gracefully. You wrap the
whole thing and handle them concurrently. Both solve the problem of trapping
exceptions - one is a more structured way to do it. We aren't all going to
use the same techniques. I obviously think mine is better, because that is
what I choose to use. You obviously disagree, hence your choice.
I find it odd that you don't (1) understand what I'm doing, and (2) assume
that, because it is not standard according to your philosophy, it is not a
"Best Practice." Best Practices are developed by people with a lot of hard
experience, and philosophizing about software doesn't create them.
Experience does.

I was imprecise with my language, so let me clear this up. The original
question was one of whether or not this was a standard. You asserted that it
certainly was not. I asserted that it was, and then provided a link to the
standard itself. I find that to be, at a minimum, compelling. However, as a
technique that works for you, it certainly is a best practice, so forgive
the sloppiness of my writing. It is a best practice, but it is not a
standard.
I can tell you this: I write a lot of robust, pretty-well-optimized
software. It does what it is intended to do, with a very small percentage of
failure. Regardless of the characterization that you may put upon my
practices, I think that whether or not they achieve that goal is the best
measure of them.

Absolutely, and I certainly don't want to disparage what you are doing, as I
said before. There are all kinds of standards out there, and there are
plenty of people who break the rules.

I think it behooves everybody to know the rules, so they can decide
knowingly when it is appropriate to break them. I see it as the difference
between spending a year reading Wrox books and spending a year getting a
Masters degree in computer science at an ivy league school. The guy who gets
the degree in computer science may not have the practical tips and tricks
down yet, but knowing the fundamentals they are more likely to become an
amazing programmer, whereas the person who only reads the practical how-to's
without understanding the fundamentals is destined to never be more than a
good programmer. But, with as many bad programmers as there are in the
world, I'm willing to settle for good. However, I think it's worthwhile to
struggle for great.

--
Chris Jackson
Software Engineer
Microsoft MVP - Windows XP
Windows XP Associate Expert
--
 
Usually a given method only has one or two exceptions that is can raise to
the caller. That method may change how it is implemented in the future, but
it usually won't change the types of exceptions that it raises. If it did,
I would consider that breaking compatibility. Any compatibility changes
should be well documented in a changelog for the new version. If the
functionality of the object changes that much you should review your code
anyway.

For example, the indexer (Item property) on a Collection will never raise
more than an "ArguementOutOfRangeException", no matter how the
implementation changes. What other logical error can possibly happen?
Don't include things like memory related exceptions as those can occur at
any point in any code.

The most important thing to keep in mind about exceptions is that objects
that use resources and require disposal should be disposed of in a finally
clause. Once you allocate the resource, the rest of the code until the
disposal should be enclosed in a try block, and the disposal in the finally
clause. It doesn't matter what the exception is, just dispose of the
resource.

The second purpose of exceptions would be to control your program flow as in
one of the (5+) I mentioned earlier. (Although you should use other ways to
control program flow if available, since exceptions are expensive.) If you
don't know what the exception is (because it is new to the current version)
then you wouldn't have been able to use it to control program flow using the
previous version. Thus the first time it is logged, you'll realize you have
a new type of exception to handle logically.
 
Man, this is beginning to get boring.

1. There is a significant difference between Standards and what you refer to
as Standards. Standards are created by organizations such as ISO and ANSI.
The document you pointed to
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/ht
ml/cpconbestpracticesforhandlingexceptions.asp) is hardly a standard. It is
an article in the MSDN Library. I have written articles for MSDN as well,
including a "Best Practices" article regarding ASP development. These are
hardly Standards by any stretch of the imagination. They are the thoughts,
experiences, and opinions of individual developers who have had a lot of
experience in the technology they write about. Standards are developed over
a long period of time by a large number of people working in concert.

2. You will note that in my original message I said "No" to the question of
whether the practice you described was a Standard. Note that I didn't say
there was anything wrong with it, just that it is not a Standard. It is not.
There is no Standard. I then gave an example of a different method for
handling some errors (which I employ in most of the software I write, due to
the nature of that software), and that started this whole mess. Apparently
you misread my remark as some advocacy of some sort for one technique over
another. I was simply opening possibilities for this person. I am the last
person to advocate following anyone, or restricting creativity. It is
creativity and the loosening of restrictions that fosters innovation and
invention.

2. NOTHING in the article you mentioned contradicts my technique. In fact, I
use ALL of the techniques mentioned in the article in my development. Take
another look, and tell me where the article states that putting an outer
Try/Catch block around a method is wrong. I took a good long look, and it
ain't there.

3. I could count the number of VB6 projects I have done on one hand, and
have fingers left over.

4. I think it behooves everyone to know the difference between rules and
opinions. I know altogether too many "monkey see monkey do" developers out
there, and they're pretty lousy at it for the most part. Nothing new is ever
discovered by following the leader. Especially when you reach the point
where you ARE a leader and you realize that these guys aren't gods; they're
just people like you.

5. I think that both reading books and spending a year getting a Masters
degree fall into the same category, and neither of them will make someone a
good developer. I buy about 2 books a year, which I use to "get my feet wet"
in a new technology, after which I rely almost exclusively upon SDKs and
other authoritative reference material, as well as experimentation and
research among a wide variety of sources, mostly on the Internet. Reading
books and going to school will only make a student as good as their teacher.
Hardly the sort of thing to make one an expert. Remember that school
teachers don't make the big bucks. So how good can they be at what they
teach? If they were good enough to make the big bucks they would. I believe
that is where we get the old saying "Those who can do; those who can't
teach." They make a good starting point, but I would argue that anyone who
stays in school long enough to get a Masters degree is likely a slow
learner.

6. My philosophy about what makes a good developer is one who works hard to
understand all of the tools and technologies avilable, and understands the
principles involved. Principles are much more useful than methodologies, as
methodologies are limited, and principles can be applied in creative and
innovative ways. It is the difference between Newton and Einstein. Laws are
useful to a point, but principles are much more powerful, and open up
possibilities that haven't been explored by those who restrict themselves to
what has been done before. Of course, it is much easier to simply follow;
the paths have already been cleared. But I am not willing to settle for
good. The Great beckons to me, and while I may never achieve it, the effort
alone makes the trip worthwhile.

7. An open mind is a teachable mind.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
http://www.takempis.com
Neither a follower nor a lender be.
 
I don't think I disagree with you? I think we have a communication gap.

If a new exception type is thrown with a new version of an assembly you use,
then your code that depended on the previous version is going to break.
Your choice is if your code will crash, or you'll be using the wrong logic.

For example:
=========================================================================
void MyMethod()
{
//simple variable declarations/ initializations.
DangerousClass _myInstance = new DangerousClass()
try
{
... code using _myInstance that could cause exception
}
catch (SpecializedDocumentedException exSpec)
{
... handle special error type ...
}
catch (Exception exGeneric)
{
... your standard logging of potentially new exceptions ...
throw new ApplicationException("Unknown exception in MyClass.",
exGeneric);
// pass this up to client since you don't know the effects of such
an undiscovered exception type.
// i wouldn't recommend continuing on without knowing the effects of
an unknown exception.
}
finally
{
_myInstance.Dispose(); //or other cleanup logic related to
DangerousClass
}
}
=========================================================================

Does this make a little more sense? Of coarse it gets more complicated if
you have more than one "dangerous" type. In the case where the second type
uses the first, you may end up with multiple nested try-catch-finally
blocks. Such as...
=========================================================================
void MyMethod2()
{
//simple variable declarations/ initializations.
DangerousClass _myInstance = new DangerousClass()
DangerousClass2 _myInstance2; //uses "DangerousClass"
try
{
_myInstance2 = new DangerousClass2(_myInstance)
.. can use _myInstance here ...
try
{
.. can also use _myInstance here ...
... use _myInstance2 here
}
catch (SpecializedDocumentedException2 exSpec2) //only catch
exception by "DangerousClass2"
{
...handle special error type ...
}
finally
{
_myInstance2.Dispose(); //or other cleanup logic related to
DangerousClass2
}
}
catch (SpecializedDocumentedException exSpec) //exception raised by
"DangerousClass"
{
... handle special error type ...
}
catch (Exception exGeneric)
{
... your standard logging of potentially new exceptions ...
throw new ApplicationException("Unknown exception in MyClass.",
exGeneric);
// pass this up to client since you don't know the effects of such
an undiscovered exception type.
// i wouldn't recommend continuing on without knowing the effects of
an unknown exception.
}
finally
{
_myInstance.Dispose(); //or other cleanup logic related to
DangerousClass
}
}
=========================================================================

Of coarse they don't have to be nested such as:
=========================================================================
void MyMethod3()
{
//simple variable declarations/ initializations.
DangerousClass _myInstance = new DangerousClass()
DangerousClass2 _myInstance2 = new DangerousClass2()
//both classes independant in this example...
try
{
... code using either "dangerous" class type that could cause
exception
}
catch (SpecializedDocumentedException exSpec) //exception type raised by
"DangerousClass"
{
... handle special error type ...
}
catch (SpecializedDocumentedException2 exSpec2) //exception type raised
by "DangerousClass2"
{
... handle special error type ...
}
catch (KnownCommonException exComm) //can be thrown by either type of
class
{
... handle known generic error here ...
}
catch (Exception exGeneric)
{
... your standard logging of potentially new exceptions ...
throw new ApplicationException("Unknown exception in MyClass.",
exGeneric);
// pass this up to client since you don't know the effects of such
an undiscovered exception type.
// i wouldn't recommend continuing on without knowing the effects of
an unknown exception.
}
finally
{
_myInstance.Dispose(); //or other cleanup logic related to
DangerousClass
}
}
=========================================================================

This is only a small sample. I couldn't comment on your situation without
knowing more about it. There is no single way to handle exceptions.

The key is that you usually handle all unknown exception types in the same
way. I pass them up to the client ulitmately. The user should ultimately
see these types of critical unrecognized exceptions. This does not mean the
app will crash. In the UI, place a try block around the entire contents of
methods. The catch block should display the error in a message box. Such
as:
=========================================================================
public class MyForm{
public void SomeMethod(...)
{
... declare types here ... no init of complex types.
try
{
.. all work here ...
}
catch (KnownExceptionType exK)
{
... display custom user friendly message with problem ...
... IE. "File does not exist", "Network Connection lost.", etc...
}
catch (Exception ex)
{
MessageBox.Show(this, ex.ToString());
// displays entire exception stack modally to this current form
// user to be instructed to report these bugs,
// or use automated report system like Microsoft.
}
}//end method
}//end form
=========================================================================

I hope this helps.
 
Michael Lang said:
I don't think I disagree with you? I think we have a communication gap.

If a new exception type is thrown with a new version of an assembly you use,
then your code that depended on the previous version is going to break.
Your choice is if your code will crash, or you'll be using the wrong
logic.

No, Michael, your choice is to write code that won't break, to begin with.
Don't write code whose correctness depends on an exception being thrown. For
instance, it makes sense to catch a specific exception (which means catching
its derived classes if it's not sealed) and doing something different in
control flow, or doing something special with properties of the exception.
But it should not be the case that your program will function incorrectly or
in an unknown manner if some new exception should happen to be thrown.

At some point in the future, C# and VB.NET may gain something like a
"throws" clause in Java. That would allow the kind of programming where you
actually _depend_ on the set of exceptions which could be thrown. In this
case, the program wouldn't compile if called methods began returning new
exception types, and your code would have to catch every exception type
which can be thrown.

Until then, there is, as far as I know, no contract between the developer of
a class library and its users, stating that the set of exceptions will not
change. This implies that your code has to be able to deal with any such
changes.

....
The key is that you usually handle all unknown exception types in the same
way. I pass them up to the client ulitmately. The user should ultimately
see these types of critical unrecognized exceptions.

I agree that _someone_ should see them, but whether the user should see them
depends on the user. I do things like display "Can't insert new data - maybe
this is a duplicate?" if I get one of the exceptions which can result from
that, otherwise "Can't insert new data". In both cases, the full exception
is logged.
 
Back
Top