Using IDisposable to write cleaner code
So I thought I’d share it here just in case you have not seen it.
IDisposable
IDisposable
is usually used as a marker interface to let programmers know that a class should be disposed of when it is no longer needed. It is quite useful when class references some unmanaged resources. Also for costly managed resources this interface could be used to clean up the memory footprint of the objects when we are done with them. You may read more about it on MSDN.
Despite the common belief Garbage Collector has no interest in IDisposable
and the interface is only useful for programmers which is what makes this trick safe to implement. One of the things that makes IDisposable
so popular and useful is the using
statement. I assume that you know the statement. If not, please refer to MSDN before reading further.
The not so readable code
So this is the code I am trying to clean:
namespace IDisposableForCleanup
{
using System;
class Program
{
static void Main()
{
DisplayWelcomeNotes();
DoSomeWork();
DisplayExitNotes();
}
private static void DoSomeWork()
{
Console.WriteLine("doing some work");
try
{
Console.WriteLine("and doing more work");
throw new Exception("Some dummy exception that we can survive");
}
catch
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("oops there was an exception but I was able to survive it");
Console.ForegroundColor = ConsoleColor.White;
}
Console.WriteLine("My work is done...");
}
private static void DisplayWelcomeNotes()
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Welcome to this very useful app");
Console.ForegroundColor = ConsoleColor.White;
}
private static void DisplayExitNotes()
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine();
Console.WriteLine("Thanks for using this very useful app");
Console.WriteLine("Press enter to exit");
Console.ForegroundColor = ConsoleColor.White;
Console.ReadLine();
}
}
}
It is a very simple console application that prints a few lines of text on the console using different colors for different bits of text. Not very useful, I know… and when you run the application you get an even less exciting output:
As shown in the code, every time we set foreground color within a scope we have to reset it back to its default value when leaving the scope which is not very nice. In fact, that code is a bit flawed because the code surrounded by the color changes should be in try-finally block to guarantee that even in the face of an unhandled exception the color is going to be reset. This is a very small application and the code smell may not be that bit a deal; but in a real codebase this smell could make your application stink.
So let’s clean that up. IDisposable
interface and using
statement are usually used for memory management; but in this trick we use them only to clean up the code. In puristic point of view and according to Framework Design Guidelines this solution is wrong; but honestly with all due respect I prefer to have a clean codebase than to comply with some guideline. The solution
I will create a small class I call ForeColor:
namespace IDisposableForCleanup
{
using System;
public class ForeColor : IDisposable
{
private readonly ConsoleColor _previousColor;
public ForeColor(ConsoleColor foreColor)
{
_previousColor = Console.ForegroundColor;
Console.ForegroundColor = foreColor;
}
public void Dispose()
{
Console.ForegroundColor = _previousColor;
}
}
}
A very simple class which implements IDisposable
. In implementing the interface I am not releasing any unmanaged and/or heavy resources. All the class does is that when it is constructed it memorizes the current console foreground color and when it is disposed it sets back the foreground color to that value. That is all.
Now let’s use this class in our little app:
namespace IDisposableForCleanup
{
using System;
class Program
{
static void Main()
{
DisplayWelcomeNotes();
DoSomeWork();
DisplayExitNotes();
}
private static void DoSomeWork()
{
Console.WriteLine("doing some work");
try
{
Console.WriteLine("and doing more work");
throw new Exception("Some dummy exception that we can survive");
}
catch
{
using (new ForeColor(ConsoleColor.Red))
{
Console.WriteLine("oops there was an exception but I was able to survive it");
}
}
Console.WriteLine("My work is done...");
}
private static void DisplayWelcomeNotes()
{
using (new ForeColor(ConsoleColor.Green))
{
Console.WriteLine("Welcome to this very useful app");
}
}
private static void DisplayExitNotes()
{
using (new ForeColor(ConsoleColor.Green))
{
Console.WriteLine();
Console.WriteLine("Thanks for using this very useful app");
Console.WriteLine("Press enter to exit");
Console.ReadLine();
}
}
}
}
which compared to the initial solution looks more like:
Alright, ok I admit it: it is not that different :P In fact the number of lines of code in this sample has not changed much and the solution itself is not so much more readable than before; but this is just a sample. In a bigger application with more complex scoping needs this trick could save you a lot of code duplication. more importantly you can avoid the headache when trying to reset to the previous ambiance. A good example of this is TransactionScope class that makes transaction scoping so much simpler to deal with.
You could use this trick pretty much anywhere you require some scoping; e.g. indentation, frozen objects, applying mutex within a scope and so on and so forth.
You may download the code from here.
Reference: Using IDisposable to write cleaner code from our NCG partner Mehdi Khalili at the Mehdi Khalili’s Blog blog.