Getting creative with IDisposable Part 2


In my last post, I gave some examples of how we can use the IDisposable interface in conjunction with the using statement to implement an on/off pattern wrapping around some critical region of code, even though there is no “disposable resource” involved.

Problems with using IDisposable

In this post I want to expand on the previous examples to illustrate a more general solution to that problem. In the previous post, all the examples implemented IDisposable directly in order to participate in the using statement. However, there are reasons why you might not wish to have this coupling: –

  1. Having a type implement IDisposable that has nothing to do with reclaiming of resources is somewhat misleading e.g. changing the console colour or the cursor icon. This is not what IDisposable was created for and can lead to confusion.
  2. We may not always want to call the “on” action on construction of the object; perhaps we want to use it in other scenarios.
  3. Compile-time tools such as Code Analysis and Coderush etc. may complain if you do not implement IDisposable in the “proper” way (with the Boolean overload) etc.

ISwitchable

There’s a way around this by making a new interface which I call ISwitchable, which is implemented by any classes that we want to use within the Using statement yet don’t want to implement IDisposable on (for the reasons outlined above).

image

Obviously, when we call “On” we’ll do the “on construction” action, and “off” will do the equivalent of the “Dispose()” call.

    The DisposableAdapter

So, how do we use ISwitchable within the context of the Using statement? Well, we can’t directly – obviously the using statement only works with IDisposable – so we use the Adapter pattern. This pattern shows how we can “massage” an object implementing one interface into another interface – in our case, from ISwitchable to IDisposable. We therefore create an adapter class which takes in an object that is of type ISwitchable and adapts it to work with IDisposable: –

ClassDiagram1

And here’s a (cut-down) version of the code for the adapter. All it does it delegate calls from the constructor to On, and Dispose to Off: –

image

Then we use it as follows, with the results below: –

image

  • CodeTimer simply starts a Stopwatch on On, and stops it (and outputs the time) when Off is called.
  • ConsoleColourInverter swaps the foreground and background console colours whenever On and Off are called.

image

So, we get two of these switchable “behaviours” applied onto our code; they start automatically, and then remove themselves once the using statement goes out of scope (as can be seen by the timer finishing and the console colour resetting itself). We don’t have to worry about exceptions either in the sense that because this is in a using statement, the finally block will automatically call dispose on both DisposableAdapter instances, which in turn delegate to the ISwitchable’s Off() method.

Conclusion

This is kind of reminiscent of aspect-oriented programming i.e. we’re applying a set of behaviours around some code and letting them do the work without us getting involved. Through the use of the Adapter pattern we have completely decoupled ourselves from IDispose, and with some use of generics are able to use these switchable objects within the context of a using statement pretty succinctly.

Getting creative with IDisposable Part 1


It occurred to me it might be interesting to describe some of the more unconventional uses of IDisposable that can help to make your code more readable, and even apply a kind of AOP-style coding to your code. MSDN describes IDisposable as follows: –

Defines a method to release allocated resources.

In the remarks section it states this: –

The primary use of this interface is to release unmanaged resources. The garbage collector automatically releases the memory allocated to a managed object when that object is no longer used. However, it is not possible to predict when garbage collection will occur. Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and stream

However, there is a secondary use for this interface which has absolutely nothing to do with the GC or memory allocation etc.. It comes into being because of the way that the “using” statement works in C#, which behind the scenes, simply calls Dispose() for us once the using statement goes out of scope (in a finally block). We can use this to our advantage in a number of situations where you want have the following behaviour: –

  1. Turn on something
  2. Do some code utilising that something
  3. Turn it off again
    Consider the following (contrived) example – we’re in a dark room and want to write out some text on a keyboard; in order to do that we need to turn on the light whilst we’re typing, and then turn it off when we’re finished: –

image

 

image

A more elegant way might be as follows: –

image

This is a much more readable version of code; it’s implied from the using statement what the scope of the light is. All we have to do is implement IDisposable on our Light class, and on the constructor and Dispose call the appropriate methods (bear in mind that Dispose gets called automatically once the using statement goes out of scope).

image

Easy. There are many situations where this pattern could be applied that have nothing to do with managed resources: –

  • Temporarily changing the console colour and then having it go back to what it was
  • Changing the mouse pointer to an egg-timer whilst doing some time-consuming operation and when it completes resetting it
  • Starting a Stopwatch when an operation starts and stopping it when it completes
  • Changing some settings on your UI e.g. writeable / read-only etc. when in a particular application state etc.
    In short, anywhere that you want to “temporarily” set the state of something and then reset it again. You can also chain them up: –

image

Nice. In my second post, I’ll discuss a way of generalising this class of problem and how we can decouple ourselves from IDisposable yet still retain the benefits of the using statement.