The “Within” Pattern in C#

Ziggy StardustHere’s a little pattern that I use a lot. It happens quite often that I need to perform a set of tasks in C# that are different, but all need the same set up and tear down.

Now I could use two methods, e.g.

object someResource=PerformSetUp(someParameters);
try
{
    someTask(someResource);
    if(someCondition)
        reportSomeError();
    anotherTask();
    someResource.Conclude("It was aliens");
}
finally
{
    PerformTearDown(someResource);
}

That’s a totally reasonable way of doing it. There are a few disadvantages though, it splits up the allocation and release of resources which can lead to tracking problems. It’s also a pain if you’ve got several things that need to be set up and torn down. You either end up with a lot of local variables flying around all the time or you make an object to hold the resources you need.

So I tend to use a method to do both the set up and tear down and pass into it an Action.

So the above example would become;


WithinSetUpAndTearDown((someResource)=>
{
    someTask(someResource);
    if(someCondition)
        reportSomeError();
    anotherTask();
    someResource.Conclude("It was aliens");
});

WithinSetUpAndTearDown is defined thus;

void WithinSetUpAndTearDown(Action<object width="300" height="150"> action)
{
    Handle someHandle = new someHandle.Open();
    try
    {
        using(object someResource = someDisposableAllocation(someHandle))
        {
            action(semeResource);
        }
    }
    finally
    {
        someHandle.Close();
    }
}

It’s sort of a user-defined version of the using keyword.Of course it has other uses too, there’s one particular applications that all share a particularly complex set of error handling conditions. I’ve used this pattern there too.

There is one application where I use this pattern rather a lot. C#’s “lock” keyword is really handy if you’re operating in a multithreaded environment, its big drawback is that there’s no way of specifying a timeout. This is important for deadlock resolution – a deadlock always means there’s a bug somewhere but if your concurrent operations just sit there deadlocked it may cause some pretty serious problems that you may not be aware of for some time. So you want to know. Rather than use the “lock” keyword then you can use this…

public static void WithObjectLocked(object lockMe, int waitMsecs, Action action)
{
    if(null == lockMe)
        throw new ArgumentNullException("lockMe");
    if(0 >= waitMsecs)
        throw new ArgumentException("waitMsecs must be greater that zero");

    bool gotLock = Monitor.TryEnter(lockMe, waitMsecs);
    if (!gotLock)
        throw new TimeoutException("Timeout of [" + waitMsecs.ToString() + "] milliseconds exceeded");
    try
    {
        action();
    }
    finally
    {
        Monitor.Exit(lockMe);
    }
}

Its functionality is identical to that of “lock”, but it will throw a “TimeoutException” if the lock cannot be obtained within the specified time. This at least gives you a fighting chance of finding operations that are taking far too long or are deadlocked.