Preserve properties of an object and have them restored automatically






2.91/5 (11 votes)
Dec 8, 2003
7 min read

63221

50
Simple technique to preserve the state of an object and have the state restored when a function exits
Introduction
One of the challenges of working with objects is returning property values, which you have changed, to their original state. This can mean writing the same lines of code again and again in any functions which change properties, that must be returned to the same value they possessed before your code "dirtied" the object.
This article presents what I feel is a reasonable solution that can be applied to C++, C#, VB or VB.NET, and can be understood by developers of all experience levels. For the beginner it presents an introduction to objects and issues related to object lifetime. For the advanced developers it shows us how we can take advantage of certain behaviours to save significant amounts of coding effort, and retain a uniform approach to protecting the values of objects which are shared amongst various processing sub-routines.
The Approach
The approach is very simple, it involves creating a simple class whose
constructor retains a reference to an object and then moves on to preserve known
property values, that the developer wishes to protect. I refer to such objects
as the Protectors
.
A Protector
is any class which
protects the values of another object such that when the Protector is destroyed,
the object which is being protected has its property values reset to their
initial values, which were in use at the time the
Protector
was created.
A Protected
Object is an object whose property
values can change and subsequently be automatically restored, in other words it
is guarded by a Protector
.
When a Protector
is instantiated the
object requiring protection is passed as a reference to the
Protector
, together with values which
are to be assigned to properties of the Protected
Object.
This approach works in object orientated language as instatiation and
destruction of objects automatically causes known sub-routines to be executed.
These known sub-routines are often referred to as Constructors and Destructors.
In Visual Basic, they are known as SUB NEW
and SUB
FINALIZE
.
Words of Caution
The behvior of OO languages when creating and destroying objects differs
widely. For example, in C++ when you destroy an object its destructor is called
immediately. This is not the case in VB.NET (see the documentation on
FINALIZE
for an explanation). Therefore the downloadable example is
a moredetailed and accurate demonstration of how to implement
Protector
objects, as they are
described below.
This means that two lines of code are required to utilise
Protector
objects, the first being to
create a Protector
and the second to
Dispose it.
Overview of Example
The example offered is described by the use of VB.NET code, but translation to C++ or C# is a trivial matter.
The SUB NEW
for the Protector
accepts two parameters, the first the object reference to
the Protected
Object and the second
parameter is a value which is assigned to a property of the
Protected
Object.
Therefore, in the example code below, the only two methods available on the
Protector
are the Sub New
and Sub Finalize
sub-routines. The Sub New is effectively
called by the developer creating a new
Protector
, whilst VB.NET will
automatically call the Sub Finalize routine when the
Protector
object is destroyed.
The Lifetime of the Protector
The lifetime of the protector in the example is the scope of a single
sub-routine which utilises the Protector
object. That is to say that, when the sub-routine begins the
Protector
is created, and when the
sub-routine ends the protector is automatically destroyed, a process often
referred to as "going out of scope".
The approach can be used within any scope though, eg: a
Protector
can exist at module level,
the developer can also create and destroy protectors at will using the syntax
NEW and MyProtector = Nothing, effectively creating a new
Protector
then destroying it.
Example Code
The following example code sections provide a basic outline of Protectors. In reality, writing a protector is more involved, however, the pay offs can still be significant.
Please download and study the sample code for an accurate implementation of
the Protector
concept in VB.NET.
The purpose of this example is to protect the SmoothingMode
property of a GraphicsObject
, such that the developer can
change SmoothingMode to any value during the course of a sub routine and have
SmoothingMode
returned to its original value when the sub-routine
completes.
Public Class GraphicsProtector
Dim mGraphics as GraphicsObject
Dim mSmoothingMode as SmoothingMode
'
' Constructor stores the object reference and relevant properties
'
Sub New(ByRef prObject as Graphics, ByVal pvNewMode as SmoothingMode)
mGraphics = prObject
mSmoothingMode = mGraphics.SmoothingMode
mGraphics.SmoothingMode = pvNewMode
End Sub
'
' Destructor restores values back to properties
'
Protected OverRides Sub Finalize()
mGraphics.SmoothingMode = mSmoothingMode
End Sub
End Class
The preceeding code describes a simple class which protects the
SmoothingMode
property of the specified Graphics
object. The following example now illustrates how the
Protector named GraphicsProtector
operates to ensure that the Graphics
object
SmoothingMode
property is reset to its initial value when the
sub-routine completes.
Sub DrawSmoothRectangle (ByRef prGraphics as Graphics)
' Create the protector, store the object reference
' and change the property
Dim lProtector As GraphicsProtector = New GraphicsProtector( _
prGraphics, SmoothingMode.HighQuality)
' Do some drawing
prGraphics.DrawRectangle(....)
prGraphics.FillEllipse(...)
' Now the lProtector object will go out of scope
' and automatically restore the objects property values
End Sub
The preceeding code is an outline which illustrates the kinds of methods
which may benefit from having graphical smoothing effects applied. For instance,
when prGraphics
is passed into the sub-routine
DrawSmoothRectangle
it could have a value of
SmoothingMode.HighSpeed
, which may not give the desired graphical
quality, therefore the sub-routine changes this to
SmoothingMode.HighQuality
, but the developer would then have to
ensure this property is returned to its original value of
SmoothingMode.HighSpeed
, else risk slowing down all other drawing
processes which occur after this sub-routine completes, something which is very
easy to forget and causes all maner of problems.
Using this approach, the developer no longer needs to remember to restore the value. Only one line of code is required to switch the property to its new value and have the original preserved.
The Chain of Events
DrawSmoothRectangle
is passed aGraphics
object into which the developer can draw miscellaneous shapes.- The developer switches the
SmoothingMode
to the desired quality, and has the original value preserved by theGraphicsProtector
object - The developer proceeds to draw.
- The
GraphicsProtector
object then goes "out of scope", i.e. it is automatically destroyed when the sub-routine ends. - At the time that the
GraphicsProtector
goes out of scope it restores the value ofprGraphics.Smoothing
mode to its original value.
For clarfification; rather than letting the system the destroy the object
automatically at the end of the DrawSmoothRectangle
routine, the
developer could have written
' Setting an object variable to nothing destroys the object
' being referred to (as long as no other variables refer to the object)
lProtector = Nothing
This too would have destroyed the GraphicsProtector
object
(lProtector
), but the whole point of this approach is to write as
little code as possible to achieve the maximum amount of housekeeping.
Advancing the Concept
From this simple start point the Sub New
, or constructor, can be
modified to accept values for numerous properties so that in a single line,
multiple properties are preserved and assigned, which affords the developer
great relief from repetitive coding.
Protectors can be instantiated and destroyed at will, not just at the top of sub-routines. Any time the need arises to protect some values whether its on the first or tenth line of a routine a Protector can be instantiated and manually or automatically destroyed.
Other examples of protectors are remembering the size and position of windows. The names, styles and sizes of fonts in use on a form. The style of the mouse cursor, all of which are things that the developer could change, and if not aware of the impact of such changes on successive functions erroneous conditions can arise within an application.
Conclusion
Utilising the automatic behaviour of object orientated systems provides great leverage. With a little thought elaborate schemes can be concocted from very simple techniques, the result being that small amounts of code can achieve immensely useful results, be those results measured in time saved in developement, or in later maintenance and support of code written using such techniques.
PLEASE NOTE: You must utilise Protectors as completely depicted in the example source code, otherwise you will experience very strange errors, which occur due to the .NET system disposing your objects at its discretion, as opposed to when you ACTUALLY want them disposed. (Thanks to Ian Darling for his reminder on this very important issue.)
I thank you for reading this article and for taking time to score my efforts, such that I can measure my contribution to this forum, from which I have gained immensly useful examples, and contact with people whose oppinion I hold in very high esteem.