Easy resource acquisition/disposal with yield returns

I love C#’s using keyword for quick resource acquisition/disposal. Together with foreach, it’s one of the first syntactical sugar pieces baked into C# and it’s a boon for keeping code tight, readable and maintainable.

On top of the classic usages (such as handling file streams where it’s paramount for the stream to be closed when it’s no longer needed), a second usage has quickly emerged early on (and in fact has been used for decades in similar fashions in other languages) and that’s simply defining the scope of operation pairs. A good example is transactions. In many libraries, you can use special classes whose sole purpose is to start a transaction when they construct and close it when the instance destructs or disposes.

How it works today

Another good example is logging of timing related information. One can wrap a piece of code in a using statement that will log the amount of time the code inside the scope ran for. For this, we’ll need to have a class that implements IDisposable and that calculates the time it took between the time it got constructed and the time it got disposed. A class like that may look a little like this:

private class TimeItObject : IDisposable
{
Stopwatch m_sw;
string m_name;
public TimeItObject(string name)
{
m_sw = Stopwatch.StartNew();
m_name = name;
}

public void Dispose()
{
Debug.WriteLine("Timing for {0} took {1}ms", m_name, m_sw.ElapsedMilliseconds);
m_sw.Stop();
}
}

To use it, the developer writes the following code:
using (new TimeItObject(“My scope”))
{
// Do some stuff here.
}
This is all great, but the class itself is fairly verbose. One needs to maintain members, initialize them, and in some cases assign them from the constructor to the members.

yield return to the rescue. Again.

I simply love yield return. I think it’s one of the most versatile keywords that exists in c# – especially because collections are such a pervasive feature in the language.

yield return has been used as a poor-man’s replacement for today’s async functionality, it can be used as a state machine. It’s incredibly powerful.

In this case, we’ll create a helper class called DisposableEnumerable. This will take an IEnumerable interface and turn it into something that can be used inside using() with minimal effort.

Here’s the class:

public class DisposableEnumerable<T> : IDisposable
{
IEnumerable<T> m_enumerable;
IEnumerator<T> m_enumerator;
T m_result;

public DisposableEnumerable(IEnumerable<T> enumerable)
{
m_enumerable = enumerable;
m_enumerator = enumerable.GetEnumerator();
m_enumerator.MoveNext();
}

public T Result
{
get { return m_result; }
}

public void Dispose()
{
m_enumerator.MoveNext();
}
}

The class is fairly straightforward. It takes an IEnumerable<> as an argument and immediately makes sure to move to the first item (the call to MoveNext). When disposed, the class again calls MoveNext().
 
On top of that, we’ll introduce an extension method that constructs one of these guys from an IEnumerable:
public static class Extensions
{
public static DisposableEnumerable<T> AsDisposable<T>(this IEnumerable<T> self)
{
return new DisposableEnumerable<T>(self);
}
}

 

So how do you use it?

Using this mechanism is fairly simple. Instead of writing the class as we did above, we simply write a yield return function like this:
public static IEnumerable<object> TimeIt(string name)
{
var sw = Stopwatch.StartNew();
yield return null; // Pivot point
Debug.WriteLine("Timing for {0} took {1}ms", name, sw.ElapsedMilliseconds);
}

The code is divided into two parts – the before yield return portion which will run as part of the constructor and the after yield return portion which will run as part of Dispose(). The fun bit here is that we don’t need to define members, remember passed parameters or anything – the c# compiler will do all that work for us.
 
And this is how the function is used (very similar to the original code – instead of “new”, we call AsDisposable()).
using (TimeIt("My scope").AsDisposable())
{
// Do something
}

When the using code is generated, a call to the constructor will be made, essentially making the TimeIt method execute until the first yield return . When using exits, it will call .Dispose() on the class which in turn will call MoveNext() which will call the bit that’s after the yield return.

Diminishing returns

The more complicated your resource acquisition helper, the less reason you have to use this method since the amount of code boiler-plate or otherwise will converge and the complexity of your yield return function will become bigger. This mechanism or trick is especially useful for cases where you have very simple resource acquisition/disposal you want to implement.

 
 
Advertisements
This entry was posted in Dev and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s