Why Can't You Code?
The highest form of ignorance is when you reject something you don't know anything about.
The highest form of ignorance is when you reject something you don't know anything about.
Linq-to-SQL is our ORM of choice until the Entity Framework matures – and in our projects we use a factory method to get a new reference to our database data context. Here’s what I mean:
var db = Database.GetDataContext();
The DataContext class implements IDisposable, which means that (usually) it should be wrapped in an using block:
using (var db = Database.GetDataContext())
{
... code that uses the database here ...
}
We discovered that we frequently have one liners inside the using block, and in most of these cases, we just return some quick value from the database.
This made me think if there was something I could do about this to make it into a more compact construct. The result is an extension method that lets me do all of this on one line, while also taking care of object disposal.
Introducing <IDisposable>.Using() extension method:
int userCount = Database.GetDataContext().Using(db => db.Users.Count()); // get a quick user count
Of course, this applies to any object implementing IDisposable, not just Linq-to-SQL – so it has lots of possible uses. Here’s another example:
foreach (string file in Directory.GetFiles(@"C:\TextFiles", "*.txt"))
{
string firstLine = new StreamReader(file).Using(f => f.ReadLine());
Console.WriteLine(firstLine);
}
We’re reading the first line of every file and making sure the file gets closed immediately afterwards. The extension method takes care of disposing the StreamReader, and allows you to focus on the functionality rather than the implementation.
That’s what functional programming is all about!
Extension method follows:
public static class DisposableExtensions
{
/// <summary>
/// Runs a delegate on the specified <see cref="IDisposable"/> and returns its value.
/// </summary>
/// <typeparam name="T">Type of the object implementing <see cref="IDisposable"/></typeparam>
/// <typeparam name="TOut">The type of the return value.</typeparam>
/// <param name="disposable">The object implementing <see cref="IDisposable"/>.</param>
/// <param name="func">A delegate that takes <paramref name="disposable"/> as a parameter and returns a value.</param>
/// <returns>Value returned by <paramref name="func"/> delegate.</returns>
public static TOut Using<T, TOut>(this T disposable, Func<T, TOut> func) where T : IDisposable
{
using (disposable)
{
return func(disposable);
}
}
/// <summary>
/// Runs a delegate on the specified <see cref="IDisposable"/> and does not return anything.
/// </summary>
/// <typeparam name="T">Type of the object implementing <see cref="IDisposable"/></typeparam>
/// <param name="disposable">The object implementing <see cref="IDisposable"/>.</param>
/// <param name="action">A delegate that takes <paramref name="disposable"/> as a parameter.</param>
public static void Using<T>(this T disposable, Action<T> action) where T : IDisposable
{
using (disposable)
{
action(disposable);
}
}
}