If a tree falls in a forest and there is no one there to hear it fall does it make a noise?

time to read 10 min | 1801 words

According to my code, it doesn't.

Here is the scenario, the scenario is supporting on the fly view updates for Brail. Recent changes in MonoRail meant that loading the view is now the responsability of the framework, and not the responsability of the view engine. This, however, presented a problem. Brail's view are compiled classes, but I want to allow edit & refresh cycles, so I can't force the develop to restart the application every time a view change.

So far, I handled it with a FileSystemWatcher that took care of it, but when the responsability moved to the framework, I needed to put something there that will give me the same functionality. The issue is that Brail is not the only View Engine for MonoRail (there are four that I am aware of), and Brail is the only one that needs this functionality. I should mention that FileSystemWatcher is a system resource, and as such, should be treated with care.

The solution, when it came to me, was relatively simple. Lazy events. Here is the code, which explain things better:

/// <summary>

/// Raised when the view is changed.

/// </summary>

public event FileSystemEventHandler ViewChanged

{

    add

    {

        //avoid concurrency problems with creating/removing the watcher

        //in two threads in parallel. Unlikely, but better to be safe.

        lock(this)

        {

            //create the watcher if it doesn't exists

            if (viewFolderWatcher == null)

                InitViewFolderWatch();

            ViewChangedImpl += value;

        }

    }

    remove

    {

        //avoid concurrency problems with creating/removing the watcher

        //in two threads in parallel. Unlikely, but better to be safe.

        lock(this)

        {

            ViewChangedImpl -= value;

            if (ViewChangedImpl == null)//no more subscribers.

            {

                DisposeViewFolderWatch();

            }

        }

    }

}

As you can see, there is a backend event that is doing the "real" work of handling subscribers and raising the event itself. What this gives me is to pay only for what I use. In this case, Brail needs this service, so it subscribe to the event, which causes the FileSystemWatcher to start working. When all the event subscribers are gone, the FileSystemWatcher is disposed.

This way, it make it look like it is continously watching, but it doesn't bother to do its work if there is no one who can't catch it sleeping on the watch :-)