views:

630

answers:

6

I just finished reading this article on the advantages and disadvantages of exceptions and I agree with the sentiment that Try-Catch blocks should not be used for "normal" control-flow management (don't use them like a goto). However, one author made (good) points about Maintainability and especially Performance that made me wonder about the same thing in Try-Finally blocks.

I surround every Connection open event in my ASP.NET application with a Try so that I can be sure to close the Connection in a Finally. Leaking connections is obviously NOT a good thing in a web app and I doubt I'd change this practice but what are your thoughts?

Note: I do have connections wrapped in a DAL and could close connections when the object destructor is called but this seems sketchy to me. As far as I know, you cannot count on a destructor being called in the event of an exception. Am I wrong?

+2  A: 

Use Try/Finally where it makes sense, don't try to optimize this until you actually have a problem caused by this.

Having said that, Try/Finally isn't as expensive as exceptions. Sure, they're not free, but throwing and catching an exception is more expensive than a Try/Finally block.

A "destructor" in .NET is called when the object is being garbage collected, which means it may take a long time before it is called. Use the Dispose pattern to implement deterministic resource disposal.

Lasse V. Karlsen
+19  A: 

You don't need to avoid the try {} ... finally {} pattern of coding. But as far as your connections go, since they're IDisposable, use "using" instead, since it does the same thing for you as the longer and more cumbersome try/finally block.

Dave Markle
+1 using is one of the best things in C#, something I miss in Java and definitely cleaner than lots of try {} ... finally{}.
Mark Davidson
For what it's worth, Using is also available in VB.NET (2005+). One of my favorite things ...
John Rudy
But I feel not enough things implement the IDisposable interface
borisCallens
+3  A: 

The bad thing about using try-catch block everywhere is that in consuming the exception you potentially conceal bad code. Try-finally (without the catch) does not hide exceptions, but does provide code execution guarantees. In your case, you can expect certain types of exceptions even from well formed SQL commands (like trying to insert a duplicate row) and thus I think the use of finally is well-justified. This assumes that you feel, as I do, that the connections should be short-lived and opened/closed when used and not for the life of your DAL.

EDIT: I would second @Dave Markle's recommendation. A using block is much more elegant and semantically equivalent. The only time I might favor a try-finally over using is to avoid multiple, nested usings in favor a single try-finally.

tvanfosson
you can gousing(var1)using(var2)using(var3){ theCode();}It's just sugar for nested usings
borisCallens
+1  A: 

I believe it is a much better practice to wrap the connection in a using statement (assuming the connection implements IDisposable). The dispose method will check the status of your connection and close if necessary.

Todd Friedlich
+1  A: 

A C# destructor is called when the object is garbage collected, except in a few border cases (if the app is shutting down, the finalizer thread only gets so long, after which it's just terminated). But that means you don't know when it'll be called. It may be a long time before the object gets garbage collected. So you're right, that's a bad idea.

However, try/finally is generally pointless too, because a using block will achieve the same thing more elegantly.

jalf
I wouldn't say it's "generally pointless". It can be a much more readable solution when you have many IDisposable objects to dispose of at a time. Once you nest usings a couple of times, the indentation can get oppressive.
Dave Markle
But does try/finally help much against that? (Incidentally, this is why C# needs proper RAII support ;))
jalf
A: 

As others have pointed out, try-finally is rarely needed due to having the using construct in C#. I still believe the model is a step backwards from RAII in C++ - the reason being that the burden in still on the client code to remember to use using (just as they would have to remember to use try-finally). And while using is more succinct than try-finally, it still seems unnecessarily verbose if you are used to C++, especially when you get a few levels of nesting.

I wrote a blog entry on how to mitigate that somewhat a while back:

http://www.levelofindirection.com/journal/2009/9/24/raii-and-readability-in-c.html

Phil Nash