views:

441

answers:

5

Disclaimer, I'm from a Java background. I don't do much C#. There's a great deal of transfer between the two worlds, but of course there are differences and one is in the way Exceptions tend to be thought about.

I recently answered a C# question suggesting that under some circstances it's reasonable to do this:

 try {
   some work
 } catch (Exeption e) {
       commonExceptionHandler();
 }

(The reasons why are immaterial). I got a response that I don't quite understand:

until .NET 4.0, it's very bad to catch Exception. It means you catch various low-level fatal errors and so disguise bugs. It also means that in the event of some kind of corruption that triggers such an exception, any open finally blocks on the stack will be executed, so even if the callExceptionReporter fuunction tries to log and quit, it may not even get to that point (the finally blocks may throw again, or cause more corruption, or delete something important from the disk or database).

May I'm more confused than I realise, but I don't agree with some of that. Please would other folks comment.

  1. I understand that there are many low level Exceptions we don't want to swallow. My commonExceptionHandler() function could reasonably rethrow those. This seems consistent with this answer to a related question. Which does say "Depending on your context it can be acceptable to use catch(...), providing the exception is re-thrown." So I conclude using catch (Exception ) is not always evil, silently swallowing certain exceptions is.

  2. The phrase "Until .NET 4 it is very bad to Catch Exception" What changes in .NET 4? IS this a reference to AggregateException, which may give us some new things to do with exceptions we catch, but I don't think changes the fundamental "don't swallow" rule.

  3. The next phrase really bothers be. Can this be right?

It also means that in the event of some kind of corruption that triggers such an exception, any open finally blocks on the stack will be executed (the finally blocks may throw again, or cause more corruption, or delete something important from the disk or database)

My understanding is that if some low level code had

lowLevelMethod() {
    try {
        lowestLevelMethod();
    } finally {
         some really important stuff
    }
}

and in my code I call lowLevel();

 try {
      lowLevel()
 } catch (Exception e) {
       exception handling and maybe rethrowing
 }

Whether or not I catch Exception this has no effect whatever on the excution of the finally block. By the time we leave lowLevelMethod() the finally has already run. If the finally is going to do any of the bad things, such as corrupt my disk, then it will do so. My catching the Exception made no difference. If It reaches my Exception block I need to do the right thing, but I can't be the cause of dmis-executing finallys

A: 

I think the quoted response is wrong (or maybe meant 2.0 instead of 4.0)? It sounds kinda bogus to me.

Brian
Yes, the more I read I think he meant 2.0.
djna
+1  A: 

Just to your third question:

If you have

nastyLowLevel() {
  doSomethingWhichMayCorruptSomethingAndThrowsException();
}

MyEvilCatcher() {
  try {
    nastyLowLevel();
  } catch (Exception e) {
    MyExceptionHandler(e);
  }
}

WiseCatcher() {
  try {
    MyEvilCatcher();
  } catch (LowLevelException e) {
    DoSomethingWiseSoFinnalyDontRuinAnything();
  } finally {
    DoSomethingWhichAssumesLowLevelWentOk();
  }
}

I think the response you asked about just meant that some low level methods could use exceptions to inform some outer method that special care has to be taken. If you forget about this exceptions in your catch-all-handler and don't rethrow them, something might go wrong.

Generally, I prefer thinking carefully about which exceptions can possibly be thrown and catch them explicitely. I only use "generic handler" at the very outer level in production environments in order to log unexpected exception and present them to the customer in an well-formatted manner (including a hint to send us the log file.)

MartinStettner
Thanks. I agree with your philosophy. I was thinking that by writing MyExceptionHandler() carefully, correctly, once we actually increase our chances of getting it right. The context was a chap writing a large number of such try/catch blocks.
djna
+7  A: 

As a general rule you shouldn't catch exceptions unless:

  1. You have a specific exception that you can handle and do something about. However in this case you should always check whether you shouldn't be trying to account for and avoid the exception in the first place.

  2. You are at the top level of an application (for instance the UI) and do not want the default behaviour to be presented to the user. For instance you might want an error dialog with a "please send us your logs" style message.

  3. You re-throw the exception after dealing with it somehow, for instance if you roll back a DB transaction.

Your finally blocks always execute. Your code sample is correct - the low level method should just have try and finally. For instance an unmanaged call might know that it needs to dispose of the unmanaged resource, but this wouldn't be exposed to .Net methods calling it. That call should get rid of the unmanaged resource in its finally block, and calling managed methods can handle exceptions or just pass them on up.

If there's something in an exception that you need to handle you should re-throw the exception, for instance:

try {
    conn.BeginTransaction();
    //do stuff
    conn.CommitTransaction();
}
catch (Exception) {
    conn.RollbackTransaction(); //required action on any exception
    throw; //re-throw, don't wrap a new ex to keep the stack trace
}
finally {
    conn.Dispose(); //always dispose of the resource
}
Keith
+4  A: 

My motto is handle what you can (or need to) and let any other exceptions bubble up and catch them in an UnhandledException event.

You are correct tho, a finally block is always called (even in the event of an exception being raised in the try section) before you exit the method. So whether you want to the catch the exception on the out method or not is entirely up to you.....this should not affect the finally block being called.

James
Thanks. I agree in general with the "bubble" idea. It's pretty much what I do in Java. There were reasonable reasons for catching Exception (and rethrowing some) in the case I was looking at.
djna
Throwing custom native exceptions?
James
Right. Also see http://stackoverflow.com/questions/434839/where-do-you-like-to-catch-exceptions-and-why
peSHIr
+10  A: 

For the question #2: The author meant "Corrupted State Exceptions". They will be introduced in .NET 4.0 (CLR team announced this at PDC 2008 in this talk).

Corrupted state exceptions cannot be caught by normal catch block. Examples: Access violation, Invalid Memory.

But you might want to catch these exceptions:

  1. In main() – write to log, exit, turn off addin
  2. Very rare cases when you know that code throws exception like this (e.g. some cases with interop with native code)

To do this you should put attribute [HandleProcessCorruptedStateException] at the method where you want to catch CorruptedStateException.

To read more about these exceptions please see this MSDN article.

Alex
Not quite the question I asked, but a very interesting answer! Thanks very much.
djna