Try..Catch…Now What
Grrrrr. This is a little bit of a rant. I don't get it. I'm working on a project right now that has code like this:
public SqlConnection GetYourFavoriteConnection() { SqlConnection Conn; try { Conn = new SqlConnection(connString); Conn.Open(); } catch (Exception e) { throw new Exception(e.Message, e); } return Conn; }
Just to be clear, I'm focusing on the use of the try...catch block only. The project I'm working on is riddled with this shit code. Why is it shit code? Well, what was wrong with the original exception? Not good enough for your code?? Not as cool as a "new" Exception?? Am I missing something?
My Beef
Where's the value add? What's the point of catching an exception if you're not going to do anything with it? Here's another good one,
SqlConnection Conn; try { //do stuff with Conn } catch(Exception e) { throw new Exception(e.Message, e); } finally { if (Conn != null) { Conn.Close(); } }
I've blogged about this before and apparently I'm blogging about it now. The using statement will do heavy lifting for you. The above could be rewritten like this:
using (SqlConnection Conn = new SqlConnection("connection string")) { //do stuff with Conn here }
What's So Special About 'Using'??
The following code:
using System; using System.Data.SqlClient; namespace ConsoleApplication1 { public class Program { public static void Main(string[] args) { using (SqlConnection cn = new SqlConnection("connection string")) { } } } }
...produces this IL
.method public hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 34 (0x22) .maxstack 2 .locals init ([0] class [System.Data]System.Data.SqlClient.SqlConnection cn, [1] bool CS$4$0000) IL_0000: nop IL_0001: ldstr "connection string" IL_0006: newobj instance void [System.Data]System.Data.SqlClient.SqlConnection::.ctor(string) IL_000b: stloc.0 .try { IL_000c: nop IL_000d: nop IL_000e: leave.s IL_0020 } // end .try finally { IL_0010: ldloc.0 IL_0011: ldnull IL_0012: ceq IL_0014: stloc.1 IL_0015: ldloc.1 IL_0016: brtrue.s IL_001f IL_0018: ldloc.0 IL_0019: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_001e: nop IL_001f: endfinally } // end handler IL_0020: nop IL_0021: ret } // end of method Program::Main
Notice anything?? Like the try..finally?? Ya, the using statement will put those in for you.
It Calls Dispose For You, So What?
Well for one that means less code to write. Read here for the other. For those who do not trust the documentation here's the code for Dispose as seen through Reflector:
protected override void Dispose(bool disposing) { if (disposing) { this._userConnectionOptions = null; this._poolGroup = null; this.Close(); } this.DisposeMe(disposing); base.Dispose(disposing); }
Take note of the fact that it calls Close for you. No need to code for it...