When accessing a resource whose lifecycle must be carefully controlled, such as database or network connections, we would traditionally use a try..finally or using block in C#. Something like this:
using(var db = connectionPool.GetConnection())
{
results = db.ExecuteQuery(query);
}
or
DatabaseConnection db = null;
try
{
db = connectionPool.GetConnection();
results = db.ExecuteQuery(query);
}
finally
{
db.Close();
}
I'm not really a fan of either of these styles. The try..finally one is particularly nasty. It would be very easy to forget to call db.Close(), or to forget to put that call in a finally block. It’s also unpleasant to have to declare and initialize the db variable outside the scope of the try block. Not only is it ugly, but it means that code further down could try to access the database connection once I’ve closed it.
The using option isn't quite so bad, but as a client of the connection pool (or whoever is managing my resource), I still have to remember to call Dispose() or wrap it in a using block. It also requires that the DatabaseConnection type expose both the operations (e.g. ExecuteQuery) and the disposal mechanism, which may more naturally belong on the connection pool.
I prefer the following style:
var results = connectionPool.WithOpenConnection(c => c.ExecuteQuery(query));
With this style, there's no way we can forget to close the connection. There's also no way that we can access the connection object outside of the intended scope.
The code inside my connection pool object usually looks like one of the examples above, using using or try...finally. I've now managed to confine the use of those unpleasant constructs to just one place in the codebase, rather than repeat them every time I need to use my database.
Typically, WithOpenConnection has a generic type parameter to specify the return type. Because C# doesn't allow void to satisfy a generic type parameter, you typically need to provide two implementations of WithOpenConnection, one for when your operation has a return value and one when it doesn't. This is the only drawback I can see of this approach.
Building Quality In
A common theme in lean and agile software delivery is to build quality in. That is, rather than inspect our software for bugs after we’ve written it, we make the software inherently high quality. One way to do this is minimise the opportunity to make a mistake and introduce a bug. If we make it easier to do the right thing, we’re less likely to make a mistake. Sometimes this is referred to as setting ourselves up for success.
That principle underlies the reasons that I prefer the lambda passing style. It’s impossible to access the database connection and forget to close it, or to access a stale connection, so we should never be able cause a bug that way.

Nice post!
ReplyDeleteBut, inside WithOpenConnection Method, you have to use use the "Using" block right?
Nice. Thanks for sharing
ReplyDelete@Khalil -thanks, glad you liked it.
ReplyDelete@Mahesh - yes, you're right. You'll always need a using or try...finally construct somewhere to get exception-safe cleanup. But this way you only need it once, rather than every time you want to access the database.