Or, how to generically set and restore state when an exception is raised
I've written twice before (here and here) about making cursor changes more robust with the using statement in C#. These allow states to be reset to correct values regardless of whether or not an exception is raised during some processing. As promised at the end of the last article, today I explain how to use lambdas to easily protect any type of "resource" without having to create a new class or sprinkle your code with try/finally blocks.
To set things up and provide a bit of context, the other day in a code review, I found this:
someFlag = true;
someStartStateMethod();
// Do some work
someResetStateMethod();
someFlag = false;
Over the years, I've seen this pattern repeated, in different domains and different languages and not necessarily limited to setting a flag. Whenever I do, I ask "if an exception happens anywhere in 'do some work,' should the state be reset?" I won't say the answer should always be "yes," but I've not yet found a "no." And this case was no exception.
Since some of the places this was done was nested, I wanted a way to clean all this up that didn't involve adding try/finally blocks. Each try/finally would add another level of indentation; it would get pretty deep pretty fast. Also, it would clutter up the code with noise that didn't really have anything to do with the work needing to be done. In other words, I didn't want this:
someFlag = true;
try
{
someStartStateMethod();
try
{
// Do some work
}
finally
{
someResetStateMethod();
}
}
finally
{
someFlag = false;
}
In my last article, I separated the code actually handling the protection from the code controlling the invocation of that protection by using inheritance. I created a base abstract class to handle the general IDisposable pattern and descendent classes to handle the actual protection. In that article, I showed a class to handle changing a cursor and then changing it back to the current value.
I quickly realized this code was simply another example of that pattern. I could do the same thing as earlier and put the someStartStateMethod() and someResetStateMethod() in a descendant class. If I followed that pattern, the code under review could be something more along the lines of:
using(new ChangeSomeFlag())
using(new ChangeSomeStateMethod())
{
// Do some work
}
This is somewhat better.
However, in this case, creating a new class for each thing needing protection didn't seem too appealing. There would be a lot of small special purpose classes, some of which might only be used once. It seemed like a sledgehammer to drive a brad. For this code, I wanted to emphasize composition over inheritance.
Enter lambdas. Because lambdas allow you to treat code as data, they allow easy composition. The LINQ and Rx libraries are great examples. They provide many generic methods (e.g. Where, Select, Any) that have the ability to compose in functionality through the use of lambdas to work on specific types for specialized purposes.
In this particular case, lambdas can be used to contain the code that handles the protection and passed to a class whose sole job is to handle the invocation of that code at the appropriate time. Rewriting the previous example with a new, as yet undefined ResourceProtector class, its use looks like:
using(new ResourceProtector(() => someFlag = true, () => someFlag = false))
using(new ResourceProtector(() => someSetStateMethod(), () => someResetStateMethod()))
{
// Do some work
}
In this code, two expressions are passed to the constructor of the ResourceProtector class that handle the saving and restoring of state. Here is a single class that can be reused over and over in different situations to protect different types of resources. I think this is a beautiful example of the single responsibility principle combined with the power of lambda expressions to handle composition.
public class ResourceProtector : IDisposable
{
private bool Disposed { get; set; }
private Action EndProtection { get; set; }
public ResourceProtector(Action startProtection, Action endProtection)
{
Disposed = false;
EndProtection = endProtection;
startProtection();
}
public void Dispose()
{
DisposeInt();
GC.SuppressFinalize(this);
}
private void DisposeInt()
{
if (Disposed)
return;
EndProtection();
Disposed = true;
}
~ResourceProtector()
{
DisposeInt();
}
}
If you have any questions, suggestions or comments, please feel free to leave them below. Until next time, subscribe to the Twitter feed to get notified of future articles and hear about other development related things.