views:

4906

answers:

12

Hi,

Folks, forgive me, I'm pretty much a raw prawn when it comes to C#, and .NET generally... though I've been a professional programmer for 10 years.

I'm looking at this article: http://www.codeproject.com/KB/cs/datatransferobject.aspx on Serializable DTO's.

The article includes this piece of code:

public static string SerializeDTO(DTO dto) {
    try {
        XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
        StringWriter sWriter = new StringWriter();
        xmlSer.Serialize(sWriter, dto);
        return sWriter.ToString();
    } catch(Exception ex) {
        throw ex;
    }
}

The rest of the article looks sane and reasonable (to a noob), but that try-catch-throw throws a WtfException... Isn't this exactly equivalent to not handling exceptions at all?

Ergo:

public static string SerializeDTO(DTO dto) {
    XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
    StringWriter sWriter = new StringWriter();
    xmlSer.Serialize(sWriter, dto);
    return sWriter.ToString();
}

Or am I missing something fundamental about error handling in C#... It's pretty much the same as Java (minus checked exceptions), isn't it? ... i.e they both refined C++.

I did search: Both SO and google, and failed to find an "authorative answer" to exactly this question... though this thread seems to support my contention that try-catch-throw is-a no-op.

Cheers all. Thanx for your time.


EDIT:

Just to summarise for anyone who finds this thread in future...

DO NOT

try {
  // do stuff that might throw an exception
} catch (Exception e) {
  throw e; // this destroys the strack trace information!
}

The stack trace information can be crucial to identifying the root cause of the problem!

DO

try {
  // do stuff that might throw an exception
} catch (SqlException e) {
  // log it
  if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
    // do special cleanup, like maybe closing the "dirty" database connection.
    throw; // this preserves the stack trace
  }
} catch (IOException e) {
  // log it
  throw;
} catch (Exception e) {
  // log it
  throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
} finally {
  // normal clean goes here (like closing open files).
}

Catch the more specific exceptions before the less specific ones (just like Java).

Thank you all for your time.

Cheers all. Keith.


References:

+3  A: 

You don't want to throw ex - as this will lose the call stack.

http://msdn.microsoft.com/en-us/library/ms229005.aspx

And yes, the try...catch is doing nothing useful (apart from lose the call stack - so it's actually worse - unless for some reason you didn't want to expose this information)

Duncan
I'll read through that article, once I've read through and responded to this abundance of answers. I humbly THANK YOU for your time.
corlettk
+44  A: 

First; the way that the code in the article does it is evil. throw ex will reset the call stack in the exception to the point where this throw statement is; losing the information about where the exception actually was created.

Second, if you just catch and re-throw like that, I see no added value, the code example above would be just as good (or, given the throw ex bit, even better) without the try-catch.

However, there are cases where you might want to catch and rethrow an exception. Logging could be one of them:

try 
{
    // code that may throw exceptions    
}
catch(Exception ex) 
{
    // add error logging here
    throw;
}
Fredrik Mörk
Thanks Richard :o)
Fredrik Mörk
@Fredrick, just fyi (though you probably know) if you're not going to use that `ex` object, then there's no need to instantiate it.
Eoin Campbell
@Eoin: I am aware of that. In this case I suggested to catch the exception in order to do something (such as logging) with it before rethrowing, and then I will need the exception instance. Good point though.
Fredrik Mörk
@Eoin: If its not instantiated it'd be rather difficult to log it.
Boo
@Fredrik: I think 'evil' is a little bit strong. It might not be very useful to do `throw ex`, but there are no negative side-effects when you do so other than losing the call stack information.
0xA3
@divo; yes, it's a bit strong, agreed. But I have seen this done by mistake so many times (and not once, I think, where it was a good idea), so I wanted to make a clear statement.
Fredrik Mörk
Yep, I think "evil" is about right... consider the case of null pointer exception thrown somewhere from a large body of code. The message is vanilla, without the stack trace you're left with "something was null somewhere". NOT good when production is dead; and you've NO minutes or less to work out the flamin' problem is, and dismiss or rectify it... Good exception handling is worth it's weight in gold.
corlettk
A: 

A valid reason for rethrowing exceptions can be that you want to add information to the exception, or perhaps wrap the original exception in one of your own making:

public static string SerializeDTO(DTO dto) {
  try {
      XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
      StringWriter sWriter = new StringWriter();
      xmlSer.Serialize(sWriter, dto);
      return sWriter.ToString();
  }
  catch(Exception ex) {
    string message = 
      String.Format("Something went wrong serializing DTO {0}", DTO);
    throw new MyLibraryException(message, ex);
  }
}
edosoft
Thanx, yep exception wrapping (especially chained) is perfectly sane... what is not sane is catching an exception just so you can chuck away the stack trace, or worse, eat it.
corlettk
+17  A: 

Don't do this,

try 
{
...
}
catch(Exception ex)
{
   throw ex;
}

You'll lose the stack trace information...

Either do,

try { ... }
catch { throw; }

OR

try { ... }
catch (Exception ex)
{
    throw new Exception("My Custom Error Message", ex);
}

One of the reason you might want to rethrow is if your handling different exceptions e.g.

try
{
   ...
}
catch(SQLException sex)
{
   //Do Custom Logging 
   //Don't throw exception - swallow it here
}
catch(OtherException oex)
{
   //Do something else
   throw new WrappedException("Other Exception occured");
}
catch
{
   System.Diagnostics.Debug.WriteLine("Eeep! an error, not to worry, will be handled higher up the call stack");
   throw; //Chuck everything else back up the stack
}
Eoin Campbell
Why not just leave catch { throw } out altogether?
AnthonyWJones
added an example as to why, but yeah, in that contrived case, you could leave it out.
Eoin Campbell
there's still value in leaving catch {throw; } at the bottom of a list of specific exception type catch's on the grounds it proves the author considered the case, though a comment might equally suffice. Not guessing when you read code is a good thing.
annakata
Eoin, THANK YOU for the succinct (and now complete) example... This is IMHO exactly what the textbook should say at the start of the exception handling chapter... the rest of guff can wait, but that's the guts of the issue in a tea cup. Cheers. Keith.
corlettk
For some reason, the name of the SQLException bothers me.
Michael Myers
That catch (Exception) { throw new Exception(...) } is something you should **never, ever, ever** do, simply because you're obfuscating the exception information and making exception filtering further up the call stack unnecessarily difficult. The only time you should catch one type of exception and throw another is when you are implementing an abstraction layer and you need to transform a provider-specific exception type (e.g. SqlException versus XmlException) into a more generic one (e.g. DataLoadingException).
jammycakes
+1  A: 

it depends what you are doing in the catch block, and if you are wanting to pass the error on to the calling code or not.

you might say Catch io.FileNotFoundExeption ex and then use an alternative file path or some such, but still throw the error on.

Also doing Throw instead of Throw Ex allows you to keep the full stack trace. Throw ex restarts the stack trace from the throw statement (hope that makes sense)

Pondidum
Gotcha. Thank you.
corlettk
+3  A: 

Isn't this exactly equivalent to not handling exceptions at all?

Not exactly, it isn't the same. It resets the exception's stacktrace. Though I agree that this probably is a mistake, and thus an example of bad code.

Arjan Einbu
Thank you Arjan.
corlettk
+1  A: 

In the example in the code you have posted there is, in fact, no point in catching the exception as there is nothing done on the catch it is just re-thown, in fact it does more harm than good as the call stack is lost.

You would, however catch an exception to do some logic (for example closing sql connection of file lock, or just some logging) in the event of an exception the throw it back to the calling code to deal with. This would be more common in a business layer than front end code as you may want the coder implementing your business layer to handle the exception.

To re-iterate though the There is NO point in catching the exception in the example you posted. DON'T do it like that!

Sheff
Thank you. Gotcha.
corlettk
+5  A: 

C# doesn't support CIL "filtered exceptions", which VB does, so in C# one reason for re-throwing an exception is that you don't have enough information at the time of catch() to determine whether you wanted to actually catch the exception.

For example, in VB you can do

Try
 ..
Catch Ex As MyException When Ex.ErrorCode = 123
 .. 
End Try

...which would not handle MyExceptions with different ErrorCode values. In C#, you would have to catch and re-throw the MyException if the ErrorCode was not 123:

try {
 ..
}
catch(MyException ex) {
 if (ex.ErrorCode != 123) throw;
 ..
}
bzlm
Good point about the filtered exceptions!
Dave Van den Eynde
Dave, but (in java at least) you wouldn't throw a "generic" MyException, you'd define a SPECIFIC exception type and throw it, allowing it to be differentiated-by-type in the catch block... But yes, if your not the architect of the exception (I'm thinking JDBC's SQLException (Java again) here, which is disgustingly generic, and exposes getErrorCode() method... Hmmm... You've got a point, it's just that I think there's a better way to do it, where possible. Cheers Mate. I appreciate your time, a lot. Keith.
corlettk
Well, the question is "Why catch and rethrow Exception in C#?", and this is an answer. =] ...and even with specialized exceptions, Exception Filters make sense: consider the case where you are, let's say, handling a SqlTimeoutException and a SqlConnectionResetException, which are both SqlException. Exception Filters let you catch an SqlException only when it's one of these two, so instead of cluttering your try/catch with identical handling for these two, you could "catch SqlException ex when ex is SqlTimeoutException Or ex is SqlConnectionResetException". (I'm not Dave btw)
bzlm
Hey, I didn't write the answer :) I just fixed the code.
Dave Van den Eynde
+1  A: 

One possible reason to catch-throw is to disable any exception filters deeper up the stack from filtering down (random old link). But of course, if that was the intention, there would be a comment there saying so.

Brian
I didn't get what you where on about until I read the link... and I'm still not exactly sure what you're on about... me being totally unfamiliar with VB.NET. I think it results in the sum being reported "inconsistent", right?... I'm a BIG fan of static methods.. apart from them being simple, there's less chance of inconsistency if you seperate the setting of attributes from the code which does the actual work. The stack is "self cleansing".
corlettk
People expect that when they write "try { Foo(); } finally { Bar(); }" that nothing runs between Foo and Bar. But this is not true; if your caller added an exception filter, and there is no intervening 'catch', and Foo() throws, then some other random code from your caller will run before your finally (Bar) runs. This is very bad if you've broken invariants or elevated security, expecting that they'll be 'immediately' restored to normal by the finally and no other code will see the temporary change.
Brian
+3  A: 

Sorry, but many examples as "improved design" still smell horribly or can be extremely misleading. Having try { } catch { log; throw } is just utterly pointless. Exception logging should be done in central place inside the application. exceptions bubble up the stacktrace anyway, why not log them somewhere up and close to the borders of the system?

Caution should be used when you serialize your context (i.e. DTO in one given example) just into the log message. It can easily contain sensitive information one might not want to reach the hands of all the people who can access the log files. And if you don't add any new information to the exception, I really don't see the point of exception wrapping. Good old Java has some point for that, it requires caller to know what kind of exceptions one should expect then calling the code. Since you don't have this in .NET, wrapping doesn't do any good on at least 80% of the cases I've seen.

Thank you for your thought Joe. In Java (and C#, I suppose) I would love to see a class-level annotation @FaultBoundary which forces ALL exceptions (including unchecked exception-types) to be caught-or-declared-to-be-thrown. I would use this annotation on public interfaces of each architectural layer. So the @FaultBoundary ThingDAO interface would not be able to leak implementation details such as SQLExceptions, NPE's, or AIOB's. Instead "causal" stacktrace would be logged and a DAOSystemException would be thrown... I define System exception as "permanently fatal".
corlettk
+2  A: 

My main reason for having code like:

try
{
  //Some code
}
catch ( Exception e )
{
  throw;
}

Is so i can have a breakpoint in the catch, that has an instantiated Exception object. I do this a lot while developing/debugging. Of course the compiler gives me warning on all the unused e's, and ideally they should be removed before a release build.

They are nice during debugging though.

Jakob
Yeah, I'll pay that one, but yes, you wouldn't want to see that in _published_ code... ergo: I would be ashamed to publish it ;-)
corlettk
Actually, this isn't necessary -- in Visual Studio you can set the debugger to break when an exception is thrown and it brings up the exception details in an inspector window for you.
jammycakes
+1  A: 

In addition to what the others have said, see my answer to a related question which shows that catching and rethrowing is not a no-op (it's in VB, but some of the code could be C# invoked from VB).

erikkallen
I thank you for your thoughts... See also http://www.pluralsight.com/community/blogs/keith/archive/2005/03/31/7149.aspx by Keith Brown and linked by Brian (a very naughty boy no doubt) on July 30 2009.
corlettk