Search code examples
c#dispose

Dispose of objects in reverse order of creation?


I face a recurring problem in the code I write: modifying some global value (I'll use a registry value just as an example) and then trying to revert the modifications to original state.

I thought I'd try to use IDisposable to solve this problem. When created, the object would read the registry value, store it locally, and then modify it. When destroyed, it would revert the setting. It would be used something like this:

using(RegistryModification mod = new RegistryModification("HKCR\SomeValue", 42))
{
    // reg value now modified to 42, do stuff
} // Object gets disposed, which contains code to revert back the setting

Should work great, if only 1 modification is ever made. But if multiple modifications are made, or the caller does not create the objects with the 'using' construct, I can see trouble occuring.

public void Foo()
{
    // assume HKCR\SomeValue starts as '13'

    // First object reads HKCR\SomeValue and stores '13', then modifies to 42
    RegistryModification mod1 = new RegistryModification("HKCR\SomeValue", 42); 

    // Next object reads HKCR\SomeValue and stores '42', then modifies to 12
    RegistryModification mod2 = new RegistryModification("HKCR\SomeValue", 12);

}
// objects are destroyed. But if mod1 was destroyed first, followed by mod2,
// the reg value is set to 42 and not 13. Bad!!!

The problem worsens if a caller manually disposes the object. This leads me to think my approach is, simply, flawed.

Is there some sort of accepted pattern to solve this problem? I was thinking adding a static stack to the class might help.

Is the order that objects are destroyed guaranteed in any way? I thought I'd try with IDisposable, but am all ears for other solutions.


Solution

  • IDisposable does not guarante a rollback in this fashion what you are describing is a rollback. The Dispose() method is not meant for that purpose rather it is responsible for the releasing of native resources that the object holds (network connections, files etc)

    However a way to revert to state could be done like this

    public void Foo(SomeObjectType theObject)
    {
        int initialValue = theObject.SomeProperty;
        theObject.SomeProperty = 25;
        Console.Out.WriteLine("Property is:" + theObject.SomeProperty);
    
        // reset object.
        theObject.SomeProperty = initialValue;
        Console.Out.WriteLine("Property oringinal value is:" + theObject.SomeProperty);
    }
    

    Remember just because a resource is disposed of it does not reverse actions that were performed using it, if you dispose of a database connection it does not undo work carried out with it, just destroys the object.

    Unless you override Dispose() with rollback code, which is a misuse of that method, then it will not pull out your values, that is your resonsibility as the programmer. The reason I say it is a misuse of the dispose method is because the .net documentation states the following for Dispose()

    Use this method to close or release unmanaged resources such as files, streams, and handles held by an instance of the class that implements this interface. By convention, this method is used for all tasks associated with freeing resources held by an object, or preparing an object for reuse.

    This generally means for example freeing handles to heavyweight stuff ( say for example some GDI resource). Native resources must be freed or sometimes placed into a certain state to avoid memory leaks or unwanted consequences of access. It is easy to say in this case that perhaps in your Dispose method you should set your registry back to the state it was before, but It is my view this is not the intent of the dispose method. The intent is to release resource and put them back into a state where they can be used again. What you want to do is reset a value (which is essentially another set operation), Doing that work in a custom dispose method means you also shorted reuse opportunities later in different contexts.

    What I am saying is that when you have finished modifying you must write explicit code to set the objects back to their initial state. You could probably store this in a data structure (say a stack) and read back the values if there were multiple operations, or just use a simple method like above for one operation.