Preserving the context of an operation

In game programming you often have certain parts in your code where you need to change some variables and reset them back afterwards (e.g. render states). This can be necessary in “regular” programs, too. Usually you save the context in some variables, perform the changes you need and revert the changes. In this post I want to show how to do it more conveniently.

The principle is clear. We need to save the value and reset it after the operation. However, instead of doing it manually, we create a class for this task, the PropertyFieldSaver. In order to mark the part after which the context is reset we use the using statement. So the code will look like this:

//before custom operation
using(var saver = new PropertyFieldSaver(...))
{
   //change some variables
}
//variables that are tracked by the saver are reverted

To support this statement, the PropertyFieldSaver has to implement the IDisposable interface. The class’ constructor is responsible for saving the variables and the Dispose method is responsible for reverting the variables.

The saver should support the tracking of properties and fields. We use a LINQ expression and reflection to save those. Furthermore, we need to save the object whose field or property is tracked:

class PropertyFieldSaver<TParent, TProperty> : IDisposable
{
    TProperty saveProperty; //the saved value
    PropertyInfo property; //if we save a property, this is its reflection info
    FieldInfo field; //if we save a field, this is its reflection info
    TParent parent; //the parent

    public PropertyFieldSaver(TParent parent, Expression<Func<TParent, TProperty>> property)
    {
        this.parent = parent;

        var expr = (MemberExpression)property.Body;
        this.property = expr.Member as PropertyInfo;
        if (this.property != null)
            saveProperty = (TProperty)this.property.GetValue(parent);
        else
        {
            this.field = expr.Member as FieldInfo;
            saveProperty = (TProperty)this.field.GetValue(parent);
        }
    }

    public void Dispose()
    {
        if(property != null)
            property.SetValue(parent, saveProperty);
        else
            field.SetValue(parent, saveProperty);
    }
}

Basically we extract the reflection info from the expression and get / set the value. However, since this class is generic, its usage is not that comfortable. To offer type inference of the generic type arguments we create a factory:

static class PropertySaverFactory
{
    public static PropertyFieldSaver<TParent, TProperty> Create<TParent, TProperty>(TParent parent, Expression<Func<TParent, TProperty>> property)
    {
        return new PropertyFieldSaver<TParent, TProperty>(parent, property);
    }
}

Now we can use our saver as follows:

var testObject = new TestClass() { TestValue = 5 };
Console.WriteLine("Object's value is {0}", testObject.TestValue);
using (var saver = PropertySaverFactory.Create(testObject, o => o.TestValue))
{
    testObject.TestValue = 6;
    Console.WriteLine("Object's value is {0}", testObject.TestValue);
}
Console.WriteLine("Object's value is {0}", testObject.TestValue);

which will give the following output:

Object's value is 5
Object's value is 6
Object's value is 5

And since we used generic parameters and type inference we can use full IntelliSense support.

Furthermore, several savers could be combined in a collection. E.g. I created another factory class for such collection that creates the savers based on a flag parameter:

using(var saver = StateSaverFactory.CreateSavers(Save.WorldMatrix | Save.ViewMatrix))
    ...
Advertisements

, ,

  1. #1 by pragmateek on June 25, 2013 - 7:25 pm

    Nice generic implementation of a disposable wrapper.

    I’ve written a complete article about this technique here: http://pragmateek.com/c-scope-your-global-state-changes-with-idisposable-and-the-using-statement/.
    Glad to see other people are using it in real-life too. 🙂
    I’ve taken the liberty of referencing your article in mine.

    Moreover you could make your implementation even more generic using a vararg list of lambdas, so that you can scope a whole set of fields/properties.

    Regards. 🙂

  2. #2 by nicoschertler on June 25, 2013 - 7:47 pm

    Great article of yours. I wasn’t aware that someone had the same awesome idea I had ;). Thanks for referencing my article. I would do the same, but the link is already in the comment. So I’ll skip that. In my implementation the management of multiple fields / properties is handled by the factory that I mentioned in the last paragraph.
    Thanks again for reading the article 🙂

  3. #3 by pragmateek on June 25, 2013 - 8:39 pm

    Ok ,nice. too bad you don’t show more code for newcomers, because it would help those not yet used to this technique. 😉 Keep it up! 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: