Syntactic Sugar – Scopes

Edit 3/11/2009: Fixed Code Formatting (Hopefully)

Have you ever had a scenario where you needed to temporarily change some value for the duration of an operation and then you wanted to change it back again when you were done? In the MVP application I’ve been working on there is a repeated scenario that the presenter needs to make the View appear busy while it performs a service call and then return the View to its original state when the service call completes. We have an interface like the following for our views:

public interface IView
{
    // .. Other stuff
    bool IsBusy { get; set; }
}

So in the presenter you find a bunch of calls that look like this:

public void SomeLongOperation() 
{ 
    bool wasBusy = View.IsBusy; 
    try 
    { 
        View.IsBusy = true; 
        // .. Do stuff 
    } 
    finally 
    { 
        View.IsBusy = wasBusy; 
    } 
}

Yuck! This code is literally copied and pasted into every location where this sort of behaviour is required. As I’m sure you’ve gathered by now I hate the copy/paste method and will look for almost any other way of doing things. Enter the Scope pattern. Here it is in action:

public void SimplerLongOperation() 
{ 
    using (View.InBusyMode()) 
    { 
        // .. Do Stuff 
    } 
}

You’ve no doubt seen the using statement in C# before (or VB for that matter). It basically allows you to declare an item that is IDisposable at the top of the scope (inside the brackets) and then it will call the Dispose() method on your object when the end of the code block (the braces) is reached.

In order to implement the desired behaviour the InBusyMode() method needs to:

  1. record the original value of the Busy property
  2. set the Busy property to true
  3. return some object that:
    1. implements IDisposable
    2. will set the value of the Busy property back to it’s original value when it is disposed

It may be weird to think of an object affecting the state of the system when it is disposed but the problem is not actually that hard to solve. Here’s the object that does that for us:

class DisposableAction : IDisposable 
{ 
    private readonly Action _action; 

    public DisposableAction(Action action) 
    { 
        _action = action; 
    } 

    public void Dispose() 
    { 
        _action(); 
    } 
}

If you haven’t seen System.Action before it’s a standard delegate which takes no arguments and returns nothing. When you create a DisposableAction you pass in the Action that you want it execute and when you call Dispose() on it the actual action is called. It feels like taking a little chunk of code and sticking it inside a baseball before pitching the baseball to where you want the code to execute. Now we can take advantage of closures in C# to implement InBusyMode() on the BaseView class:

public IDisposable InBusyMode() 
{ 
    var wasBusy = IsBusy; 
    IsBusy = true; 
    return new DisposableAction(() => IsBusy = wasBusy); 
}

Simple right! The only hard part is on line 5 where the DisposableAction is constructed. That thing that starts with ()=> is a lambda expression which is basically just a single statement (IsBusy = wasBusy;).

Finally, this entire method can be pulled out of the BaseView class and turned into an extension method on IView. That way you’ll get the behaviour even if you don’t inherit from BaseView:

public static class ViewExtensions 
{ 
    public static IDisposable InBusyMode(this IView target) 
    { 
        var originalValue = target.IsBusy; 
        target.IsBusy = true; 
        return new DisposableAction(() => target.IsBusy = originalValue); 
    } 
}

You can use the DisposableAction class anywhere you need to pitch a change to some point later in your code. I’ve seen it used for changing status messages, renaming files temporarily, changing indenting on reports, temporarily increasing application security settings or disabling logging, and a heap of other places. I first came across it here.

design-patternssyntactic-sugar
Posted by: Mike Minutillo
Last revised: 27 May, 2011 04:23 PM History

Comments

Anonymous
Anonymous
27 Oct, 2010 07:27 PM @ version 0

This seems like a gross misuse of the IDisposable interface! It's semantics should only deal with freeing unmanaged resources, not bolting on transaction scoping!

11 Nov, 2009 03:00 AM @ version 0

Hey since u hv a blog. Hehe. U might wanna check www.ozbloggers.com. It's new & expanding :) connects via Twitter

30 Oct, 2009 04:13 AM @ version 0

Hi Jason,

Good call. No matter which Live Writer Plugin I use it always seems to stuff up somewhere. I'll have a look later today.

30 Oct, 2009 04:02 AM @ version 0

Mind working on the code sample formatting? I skipped reading the rest of your blog because the code samples had too many spaces in their formatting...

No new comments are allowed on this post.